Aplikacja bazodanowa z JDBC

W tym artykule przedstawiam podstawowe podejście do programowania aplikacji bazodanowych w języku Java z użyciem interfejsu JDBC. Kieruję go do początkujących programistów języka Java, którzy nie mają jeszcze doświadczenia z programowaniem baz danych w tym języku.

Interfejs JDBC (Java DataBase Connectivity)

Przygodę z programowaniem aplikacji bazodanowych w języku Java najlepiej zacząć od postaw. Za takie podstawy można przyjąć wykorzystanie interfejsu Java DataBase Connectivity (JDBC) do komunikacji z bazą danych.

Interfejs JDBC umożliwia komunikację z bazą danych za pomocą języka SQL: zarówno pobieranie danych (zwykle przy użyciu instrukcji SELECT) jak i zapisywanie danych (zwykle przy użyciu instrukcji UPDATE). JDBC umożliwia także wykonywanie innych instrukcji SQL, na przykład przetwarzających dane lokalnie na serwerze baz danych bez transmisji tych danych między serwerem a aplikacją.

Jak zainstalować JDBC ?

Sam interfejs programistyczny aplikacji JDBC jest dostarczany razem z JDK SE (Java Development Kit Standard Edition), nie wymaga więc żadnej dodatkowej instalacji. Potrzebny jest natomiast odpowiedni sterownik do komunikacji z serwerem baz danych, zależny od rodzaju używanego serwera. Sterowniki takie można zazwyczaj znaleźć na stronach producentów oprogramowania serwerów baz danych, na przykład na stronie http://dev.mysql.com/downloads/connector/j/ dla bazy danych MySQL lub na stronie https://jdbc.postgresql.org/ dla bazy danych PostgreSQL. Pobrane pliki należy udostępnić kompilatorowi języka Java (w zależności od używanego środowiska i jego konfiguracji może to wymagać różnych działań).

Jak skonfigurować bazę danych ?

Używanie JDBC nie wymaga żadnej dodatkowej konfiguracji ani serwera baz danych, ani samych baz danych. Należy jednak zwrócić uwagę, aby serwer akceptował połączenia z komputera, na którym będzie uruchamiana aplikacja bazodanowa z JDBC.

Programistom zazwyczaj najwygodniej jest mieć własny serwer baz danych zainstalowany na komputerze, na którym normalnie pracują, czyli piszą i uruchamiają swoje aplikacje bazodanowe. Wówczas aplikacja będzie łączyć się z serwerem baz danych na tym samym komputerze: z jednej strony aplikacja bazodanowa będzie nawiązywać połączenie z serwerem o adresie localhost, a z drugiej strony serwer będzie odbierał połączenie od aplikacji z adresu localhost.

W niektórych przypadkach serwer baz danych znajduje się na innym komputerze niż ten, na którym uruchamiana jest aplikacja bazodanowa z JDBC. Wówczas aplikacja musi znać adres sieciowy serwera, a serwer musi akceptować połączenia przychodzące z adresu sieciowego komputera, na którym uruchamiana jest aplikacja.

Połączenie z bazą danych w JDBC

Przykład kodu w języku Java, który łączy się z bazą danych używając JDBC można znaleźć poniżej.

		try {
			DriverManager.registerDriver(new org.postgresql.Driver());
			Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "iProgramujesz.pl");


			// ...



			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}

Pierwszym krokiem jest zarejestrowanie sterownika JDBC do komunikacji z odpowiednim serwerem baz danych. Używa się do tego statycznej metody registerDriver(…) z klasy DriverManager. W prezentowanym kodzie łączyć się będziemy z serwerem PostgreSQL, dla którego odpowiedni sterowniki jest reprezentowany przez klasę org.postgresql.Driver.

Drugim krokiem jest nawiązanie połączenia z bazą danych. Używa się do tego statycznej metody getConnection(…) z klasy DriverManager. W prezentowanym kodzie metodę tę wywołujemy z 4 parametrami: adresem url serwera baz danych (serwer jest zainstalowany na tym samym komputerze co aplikacja, odbiera połączenia na standardowym dla PostgreSQL porcie 5432), nazwą bazy danych (standardową dla PostgreSQL bazą o nazwie „postgres”), nazwą użytkownika bazy danych (standardowym dla PostgreSQL użytkownikiem o nazwie „postgres”) i hasłem użytkownika (hasło dla użytkownika „postgres” jest zwykle ustalane podczas instalacji serwera baz danych, w moim przypadku jest to „iProgramujesz.pl”). Metoda ta zwróci obiekt klasy Connection reprezentujący nawiązane połączenie.

Po nawiązaniu połączenia z bazą danych można wykonywać na niej operację, pobierać i zapisywać dane czy wykonywać instrukcje SQL. Na zakończenie należy rozłączyć się z bazą danych używając metody close() odpowiedniego obiektu klasy Connection reprezentującego nawiązane wcześniej połączenie.

Operacje bazodanowe w języku Java mogą powodować występowanie wyjątków klasy SQLException, więc należy zagnieździć je w bloku obsługującym te wyjątki.

Pobieranie danych z bazy danych w JDBC

Przykład kodu w języku Java, który pobiera dane z bazy danych używając JDBC można znaleźć poniżej.

			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("SELECT * FROM author");

			while(rs.next()) {
				System.out.println(rs.getInt("id") + " : " + rs.getString("name"));
			}

			rs.close();
			stmt.close();

W celu wykonywania operacji na bazie danych, należy utworzyć obiekt klasy Statement używając metody createStatement() odpowiedniego obiektu klasy Connection reprezentującego nawiązane wcześniej połączenie do bazy danych. Używając stworzonego obiektu klasy Statement można wykonać zapytanie do bazy danych i pobrać z niej dane.

Wykonanie zapytanie do bazy danych polega na wykonaniu metody executeQuery(…) wcześniej stworzonego obiektu klasy Statement. Parametrem tej metody jest instrukcja SQL reprezentująca zapytanie. W prezentowanym kodzie jest to instrukcja SELECT * FROM author pobierająca całą zawartość tabeli author. Metoda executeQuery zwraca obiekt klasy ResultSet zawierający pobrane dane.

Pobrane dane można odczytać z obiektu klasy ResultSet iteracyjnie, przechodząc pobraną tabelę wiersz po wierszu. W prezentowanym kodzie instrukcje rs.getInt(„id”) odczytują liczbę typu int z kolumny o nazwie „id” z aktualnego wiersza tabeli, a instrukcje rs.getString(„name”) odczytują łańcuch znaków z kolumny o nazwie „name” z aktualnego wiersza tabeli. Instrukcja rs.next() powoduje przejście do kolejnego wiersza tabeli reprezentowanej przez obiekt klasy ResultSet.

Na zakończenie należy wykonać metodę close() używanego obiektu klasy ResultSet oraz metodę close() używanego obiektu klasy Statement. Co prawda, w większości przypadków metody te zostaną wykonane automatycznie przy zamykaniu używanego obiektu klasy Connection, ale można zrobić to wcześniej, żeby zwolnić zasoby komputera.

Zapisywanie danych do bazy danych w JDBC

Przykład kodu w języku Java, który zapisuje dane do bazy danych używając JDBC można znaleźć poniżej.

			Statement stmt = conn.createStatement();
			stmt.executeUpdate("INSERT INTO author VALUES (1, 'Henryk Sienkiewicz')");
			stmt.executeUpdate("INSERT INTO author VALUES (2, 'Bolesław Prus')");
			stmt.close();
			conn.commit();

Podobnie jak przy pobieraniu danych, na początku należy utworzyć obiekt klasy Statement. Jego metoda executeUpdate(…) umożliwia wykonywanie instrukcji SQL zapisujących dane. Parametrem tej metody jest odpowiednia instrukcja SQL. W prezentowanym kodzie jest to instrukcja INSERT wstawiająca nowy wiersz do tabeli authors.

Na zakończenie należy wykonać metodę close() używanego obiektu klasy Statement oraz metodę commit() używanego obiektu klasy Connection, która wymusza wykonanie przesłanych instrukcji w bazie danych (baza danych może nie wykonywać przesyłanych instrukcji SQL na bieżąco, a jedynie gromadzić je i łączyć w listę instrukcji SQL zwaną transakcją, która zostanie wykonana dopiero po dodatkowym potwierdzeniu lub anulowana, jeśli takiego potwierdzenia nie będzie).

Przykład: prosta aplikacja bazodanowa z JDBC

Prosta aplikacja bazodanowa w języku Java wykorzystująca interfejs JDBC do komunikacji z bazą danych jest przedstawiona poniżej.

Do działania aplikacji potrzebne jest wcześniejsze utworzenie w bazie danych tabeli author o dwóch kolumnach: kolumnie o nazwie „id” przechowującej dane typu int oraz kolumnie o nazwie „name” przechowującej łańcuchy znaków. Tabelę taką można utworzyć następującą instrukcją SQL: „CREATE TABLE author (id INTEGER PRIMARY KEY, name VARCHAR(80) NOT NULL UNIQUE);”. Tabelę tę należy też wypełnić danymi, na przykład wykonując następujące instrukcje SQL: „INSERT INTO author VALUES (1, ‚Henryk Sienkiewicz’);” oraz „INSERT INTO author VALUES (2, ‚Bolesław Prus’);”.

package pl.iprogramujesz.tutorial.database.jdbc;

import java.sql.*;

public class DatabaseApplication {

	public static void main(String[] args) {
		try {
			DriverManager.registerDriver(new org.postgresql.Driver());
			Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "iProgramujesz.pl");
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("SELECT * FROM author");

			stmt.executeUpdate("INSERT INTO author VALUES (1, 'Henryk Sienkiewicz')");
			stmt.executeUpdate("INSERT INTO author VALUES (2, 'Bolesław Prus')");
			conn.commit();

			while(rs.next()) {
				System.out.println(rs.getInt("id") + " : " + rs.getString("name"));
			}
			
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

Uwagi na zakończenie

W artykule użyłem wielu uproszczeń, m.in. używałem sformułowania klasa Connection, Statement czy ResultSet, gdy naprawdę Connection, Statement i ResultSet to interfejsy języka Java z pakietu java.sql.

Prosta aplikacja bazodanowa z JDBC może powstać w środowisku programistycznym Eclipse

Przedstawione rozwiązanie – tworzenie aplikacji bazodanowych w języku Java wykorzystujących interfejs JDBC – jest bardzo podstawowe. W praktyce zazwyczaj wykorzystuje się bardziej zaawansowane rozwiązania, na przykład oparte na standardach JPA (Java Persistence API) lub frameworkach Hibernate czy iBatis, które opiszę w kolejnych artykułach.