Duża (jeżeli nie większość) część aplikacji korzysta z bazy danych. Zapisuje oraz pobiera z niej informacje praktycznie na okrągło i co ważniejsze, nie jest w stanie poprawnie funkcjonować bez niej. W przypadku Javy połączenia realizowane z bazą danych są opisane poprzez standard JDBC (Java DataBase Connectivity). Praktycznie wszystkie sterowniki do baz danych relacyjnych opierają się na tym standardzie i realizują opisane w nim funkcje. Ponieważ aplikacje tak silnie zależą od baz danych, często pojawiają się różne problemy związane z ich użyciem. W celu ich analizy przydatne może być możliwość sprawdzenia, jak wyglądają poszczególne zapytania do bazy danych wysłane przez aplikację, łącznie z informacje jakie dane są w nich przesyłane.

Jedną z możliwości sprawdzenia (dokładnego) jak wyglądają poszczególne zapytania do bazy danych, jest użycie specjalnego sterownika pośredniczącego pomiędzy naszą aplikacją a serownikiem bazodanowym. Pośrednik ten umożliwia zalogowanie odpowiedniego zapytania zanim zostanie ono przekazane do sterownika odpowiedzialnego za połączenie się z bazą danych i wykonywania na niej operacji. Takim sterownikiem pośredniczącym jest log4jdbc.

Instalacja biblioteki w aplikacji

Pierwszym krokiem powinno być pobranie odpowiedniej wersji biblioteki ze strony log4jdbc. Należy zwrócić uwagę, że inne wersje są zalecane w zależności od tego, jaka wersja Javy zostanie użyta do uruchomienia aplikacji. W moim przypadku najwłaściwszy był plik log4jdbc4-1.2beta1.jar.

Powyższy plik JAR należy dołączyć do ścieżki aplikacji. Ja w swoim przypadku korzystałem z aplikacji uruchomionej na serwerze aplikacyjnym JBoss, więc skopiowałem ten plik do katalogu [cc]common/lib[/cci]. Pozostał jeszcze tylko restart serwera i biblioteka jest gotowa do użycia.

Inicjalizacja połączenia

Istnieją dwa sposoby inicjalizacja biblioteki: w kodzie aplikacji poprzez wywołanie odpowiedniej klasy oraz poprzez odpowiednie utworzenie łańcucha połączenia z bazą danych w standardzie JDBC.

Inicjalizacja log4jdbc w kodzie aplikacji

Oto przykładowy kod źródłowy, jaki należy użyć w aplikacji :

1
2
3
4
5
6
7
// get connection from datasource
Connection conn = dataSource.getConnection();

// wrap the connection with log4jdbc
conn = new net.sf.log4jdbc.ConnectionSpy(conn);

// now use Connection as normal (but it will be audited by log4jdbc)

Czyli najpierw tworzymy lub pozyskujemy połączenie do bazy danych, a następnie przekazujemy je do instancji klasy ConnectionSpy, która od tej pory będzie pośredniczyć w wywoływaniu odpowiedniego kodu i logowaniu informacji przez bibliotekę log4jdbc.

Inicjalizacja połączenia przy użyciu JDBC

Drugim sposobem jest zdefiniowanie połączenia do bazy danych przy użyciu łańcucha JDBC. Robi się to dodając informację o użyciu biblioteki log4jdbc w łańcuchu definiującym połączenie. Jeżeli podstawowe połączenie z bazą danych wygląda następująco (połączenie z bazą danych MySQL):

jdbc:mysql://localhost:3306/baza_danych

To należy dodać do łańcucha ten ciąg znaków log4jdbc, tak aby wyglądał on następująco:

jdbc:log4jdbc:mysql://localhost:3306/baza_danych

Jako klasę sterownika należy użyć klasy: net.sf.log4jdbc.DriverSpy. Przykładowa konfiguracja źródła danych dla JBossa wygląda następująco:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
  <local-tx-datasource>
    <jndi-name>bazaDanychDS</jndi-name>
    <connection-url>jdbc:log4jdbc:mysql://localhost:3306/baza_danych</connection-url>
    <driver-class>net.sf.log4jdbc.DriverSpy</driver-class>
    <!-- definicja użytkownika, hasła, innych parametrów potrzebnych do połączenia z bazą danych -->
  </local-tx-datasource>
</datasources>

Biblioteka log4jdbc automatycznie postara się zaincjalizować odpowiednią klasę sterownika dla używanej bazy danych. Pełna list domyślnie używanych klas (w zależności od wybranej bazy danych) znajduje się na stronie domowej tego projektu, poniżej znajduje się wybór kilku najczęściej używanych:

Baza danych Klasa sterownika
Oracle oracle.jdbc.driver.OracleDriver
MySQL com.mysql.jdbc.Driver
PostgresSQL org.postgresql.Driver
HSQLDB org.hsqldb.jdbcDriver

Jeżeli istnieje potrzeba użycia innego sterownika do bazy danych, można te informacje przekazać do biblioteki konfigurując odpowiednią zmienną systemową log4jdbc.drivers:

-Dlog4jdbc.drivers=<driverclass>[,</driverclass><driverclass>...]

Teraz pozostaje uruchomić aplikację i w logach powinny znaleźć się informacje o zadawanych zapytaniach, o wartościach poszczególnych parametrów w zapytaniu (szczególnie pomocne w podczas używania klasy PreparedStatement).

Konfiguracja loggerów

Biblioteka log4jdbc definiuje pięć różnych loggerów odpowiedzialnych za zapisywanie różnych informacji dotyczących komunikacji z bazą danych. Każdy z nich może mieć ustawiony jeden z poziomów logowania: DEBUG, INFO, ERROR, FATAL.

Jeżeli wszystkie będą ustawione na poziom FATAL, to faktycznie log4jdbc zostanie wyłączony. Wtedy też nowo tworzone połączenie nie będą otaczane klasą ConnectionSpy tylko będzie to bezpośrednie połączenie z bazą danych. Taki sposób działania jest przydatny, ponieważ można nawet w środowisku produkcyjnym mieć zdefiniowane połączenie z bazą danych przy użyciu log4jdbc, ale włączać je za pomocą definicji odpowiednich zmiennych, bez potrzeby modyfikowania łańcucha definiującego połączenie.

Znaczenie pozostałych poziomów logowania:

  • ERROR – wypisanie stack trace w logu w przypadku wystąpienia wyjątku SQLException
  • INFO – dodanie wyświetlania poleceń SQL
  • DEBUG – dodanie nazwy klasy oraz numeru linii w której zostało wykonane dane polecenie SQL (powoduje także większy narzut czasowy na zapisanie takie informacji w logu)

Dostępne loggery:

Logger Opis
jdbc.sqlonly logowanie samych poleceń SQL, w przypadku korzystania z klasy PreparedStatement także zostaną podane wartości poszczególnych parametrów
jdbc.sqltiming informacje o czasie wykonywania poszczególnych zapytań SQL
jdbc.audit logowanie wszystkich wywołań JDBC poza wynikami (używane do wyszukiwania problemów z JDBC)
jdbc.resultset logowanie wszystkich wywołań do klasy ResultSet
jdbc.connection logowanie informacji o otwieraniu i zamykaniu połączeń, pomocne w przypadku wystąpienia problemów z wyciekami połączeń

Przykładowa fragment linii poleceń wywołującej JVM w którym są te loggery włączane:

-Djdbc.sqlonly=DEBUG -Djdbc.sqltiming=DEBUG -Djdbc.audit=INFO -Djdbc.connection=INFO

Źródła