Java #51: JDBC – połączenie z bazą danych

Aby zrozumieć dzisiejszą lekcję, musisz znać podstawy baz danych. Jeśli nie masz pojęcia czym są i do czego służą, proponuję wpierw poznać lub powtórzyć wiedzę o tym jak dokonywać prostych zapytań SQL do relacyjnych baz danych. Następnie zapoznam Cię z biblioteką JDBC.

Bazy danych – podstawowe informacje

Baza danych jest samodzielnym mechanizmem przechowywania danych. Innym sposobem do trzymania informacji jest korzystanie z obiektów i struktur danych w Javie. Nie zawsze jednak jest to optymalne. Bazy danych posiadają szereg optymalizacji, które pozwalają szybko wyszukiwać w nich informacji. Dodatkowym plusem jest to, że silnik baz danych działa niezależnie od wirtualnej maszyny Javy (z reguły). Tak czy siak, szybciej czy później będziesz mieć do czynienia z relacyjnymi bazami*.

Ponieważ, jak już wspomniałem, bazy danych są niezależnym narzędziem, z reguły posiadają wbudowany mechanizm dostępu do nich. Czasami jest to zwykła konsola (np. PostgreSQL), czasami to wyspecjalizowane narzędzie (SQL Developer lub MySQL Workbench). W obecnych czasach, coraz rzadziej bazy danych są używane jako samodzielna usługa. Z reguły są po prostu „twardym dyskiem” dla języków programowania, które umożliwiają wielowątkowe ich przetwarzanie oraz tworzenie zaawansowanego GUI-a (Graphical User Interface), dzięki któremu łatwo później wykonywać skomplikowane zapytania.

W tym wpisie skupię się na tym, jak możesz łatwo napisać program, który będzie komunikował się z dowolną bazą danych.

Połączenie z bazą z poziomu Javy

Wpierw napiszę enum, który będzie dostarczał mi informacji o położeniu bazy danych. Podstawowe informacje, które musisz tam zawrzeć to prawidłowy sterownik (dla MySql będzie to com.mysql.cj.jdbc.Driver), połączenie z Twoją instancją bazy (u mnie nazywa się ona myjdbc), oraz użytkownik z hasłem, który ma dostęp do serwera bazy danych.

public enum MysqlProperties {
	DB_DRIVER("com.mysql.cj.jdbc.Driver"),
	DB_CONNECTION("jdbc:mysql://127.0.0.1:3306/myjdbc?serverTimezone=UTC"),
	DB_USER("root"),
	DB_PASSWORD("root");
	
	private final String value;
	private MysqlProperties(String value) {
		this.value = value;
	}
	public String getValue() {
		return value;
	}
}

Dołączanie sterownika JDBC

Następnie należy napisać klasę, która korzystając z enuma MysqlProperties, połączy się z bazą. Zawiera ona metodę implementującą interfejs Connection. Wpierw należy sprawdzić, czy sterownik istnieje w Twoim projekcie. Jeśli go nie masz, to musisz ściągnąć odpowiedni plik jar** i dołączyć go w Twoim IDE do projektu, na którym pracujesz. Ja stworzyłem specjalny katalog lib w folderze projektowym i tam go trzymam. Powinieneś także pamiętać, aby był on kompatybilny z wersją serwera baz danych, do którego się chcesz połączyć.

image
Katalog do którego ściągnąłem sterownik MySQL

Aby zadeklarować w Eclipse dodatkowe biblioteki, należy kliknąć: prawy przycisk na Twoim projekcie -> properties -> w sekcji ’Java build path’ kliknij zakładkę libraries -> Add JARs.. -> wybierasz sterownik JDBC w odpowiednim katalogu.

Korzystanie z pakietu java.sql.*

Kolejny try catch to właściwa próba połączenia się z bazą. W przypadku niemożności wykonania połączenia zostanie wyrzucony wyjątek SQLException.

public final class DatabaseConnector {
	private static Logger LOGGER = Logger.getLogger(DatabaseConnector.class.getName());
	private DatabaseConnector() {
	}
	public static Connection getDBConnection() {
		Connection dbConnection = null;
		try {
			Class.forName(DB_DRIVER.getValue());
		} catch (ClassNotFoundException e) {
			LOGGER.log(Level.WARNING, "Driver not found. " + e.getMessage(), e);
		}
		try {
			dbConnection = DriverManager.getConnection(DB_CONNECTION.getValue(), DB_USER.getValue(),
					DB_PASSWORD.getValue());
		} catch (SQLException e) {
			LOGGER.log(Level.WARNING, "Can't make connection with database. " + e.getMessage(), e);
		}
		return dbConnection;
	}
}

Najlepszym sposobem trzymania zapytań SQL jest zwykły plik tekstowy. W moim przypadku trzymam go w katalogu src/main/resources/jdbc. Stworzę tu dwa pliki: jeden stworzy tabelę w mojej bazie i wypełni ją danymi, drugi za to będzie wykonywał jakieś zapytania typu select.

Przykład pliku create.sql:

DROP TABLE dbuser;
CREATE TABLE dbuser (id int, firstname varchar(100), lastname varchar(100), address varchar(200));
INSERT INTO dbuser VALUES(1, "ala", "ma", "kota"); 
INSERT INTO dbuser VALUES(2, "ala", "ma", "kota"); 
INSERT INTO dbuser VALUES(3, "ala", "ma", "kota"); 
INSERT INTO dbuser VALUES(4, "ala", "ma", "kota");

Plik z zapytaniem select.sql:

SELECT * FROM dbuser;

Tego typu pliki umiesz już wczytać, więc nie będę się na tym skupiał. W mojej implementacji metoda wczytująca zapytania zapisuje je na liście.

Klasa dostępowa do danych

Teraz należy napisać klasę, która dokonywać faktycznych zapytań do bazy.

public final class DataAccess {
	private static Logger LOGGER = Logger.getLogger(DataAccess.class.getName());
	private Connection dbConnection;
	public DataAccess(Connection dbConnection) {
		this.dbConnection = dbConnection;
	}
	public String read(List<String> selectQueries, String columnName) throws SQLException {
		Statement statement = null;
		String resultMessage = "NO SELECT RESULT";
		try {
			statement = openConnection();
			for (String query : selectQueries) {
				LOGGER.info(query);
				ResultSet rs = statement.executeQuery(query);
				LOGGER.info("Data was found! " + rs.getString(columnName));
				rs.close();
			}
		} catch (SQLException e) {
			LOGGER.log(Level.WARNING, "Driver not found. " + e.getMessage(), e);
		} finally {
			if (statement != null) {
				statement.close();
			}
		}
		return resultMessage;
	}
	public void closeConnection() throws SQLException {
		if (dbConnection != null) {
			dbConnection.close();
		}
	}
	private Statement openConnection() throws SQLException {
		Statement statement;
		if (dbConnection == null) {
			dbConnection = DatabaseConnector.getDBConnection();
		}
		statement = dbConnection.createStatement();
		return statement;
	}
}

Klasa w konstruktorze przesyła połączenie uzyskane jako wynik metody getDBConnection. Metody openConnection i closeConnection służą do otworzenia i zamknięcia połączenia z bazą danych. Z reguły, gdy otworzysz raz połączenie nie ma sensu go zamykać do momentu, kiedy to będziesz pewny, że nie wykonasz już więcej zapytań do bazy. Metoda read pozwala na odczytanie zapytań z listy (w tym przypadku muszą to być zapytania typu select). Następnie tworzony jest obiekt na podstawie interfejsu Statement. Umożliwia on skorzystanie z dwóch metod: jedna stosowana jest od odczytu danych (executeQuery) lub ich manipulacji (executeUpdate).

Ponieważ naszym celem jest odczyt danych, to executeQuery musi je zwrócić w jakiś sposób. Zapisane one będą w obiekcie ResultSet, skąd możesz odwołać się do konkretnej nazwy kolumny, aby sprawdzić jej wartość. ResultSet otwiera niejawnie tzw. kursor***, nie można go trzymać otwartego w nieskończoność, dlatego po wykonaniu wszystkich zapytań, należy go zamknąć za pomocą close. Dodatkowo w sekcji finally zamykany jest też obiekt statement.

Otwarcie połączenia i wykonanie poleceń

Teraz musisz tylko skorzystać z powyższej implementacji w swojej metodzie main.

Connection dbConnection = DatabaseConnector.getDBConnection();
			DataAccess dataAccess = new DataAccess(dbConnection);
			List<String> selectQueries = readyFrom(); // wczytanie z pliku zapytań do listy
			dataAccess.read(selectQueries, columnName);
// columnName - kolumna której wartość chcesz odczytać
			dataAccess.closeConnection();

Gratulacje! Znasz już podstawowy sposób w jaki można komunikować się z bazą danych za pomocą JDBC!

*Istnieją jeszcze inne rodzaje baz danych, np. nierelacyjne (tzw. NoSQL) .

** W moim przypadku skorzystałem z mysql-connector-java-6.0.5.jar, dostępnego pod tym linkiem: https://repo1.maven.org/maven2/mysql/mysql-connector-java/6.0.5/mysql-connector-java-6.0.5.jar

***Wyjaśnienie czym kursor na przykładzie bazy MS SQL: https://docs.microsoft.com/en-us/sql/ado/guide/data/what-is-a-cursor?view=sql-server-ver15

Stay in the Loop

Get the daily email from CryptoNews that makes reading the news actually enjoyable. Join our mailing list to stay in the loop to stay informed, for free.

Ostatnio dodane

- Advertisement - spot_img

Powiązane wpisy