Введение в Java JDBC
Что такое JDBC, как он абстрагирует доступ к базе данных в Java и какова архитектура API JDBC.
Введение в Java JDBC
JDBC (Java Database Connectivity) — это стандартный API для общения с реляционной базой данных из Java. Он расположен в пакетах java.sql и javax.sql и даёт вам один независимый от поставщика способ открыть соединение, отправить SQL и прочитать результаты — независимо от того, является ли база данных за ним PostgreSQL, MySQL, Oracle, SQL Server или встраиваемым движком вроде H2. Изучите API один раз, и при смене базы данных меняется только URL соединения.
Главная идея: тонкий, единообразный слой над многими базами данных
Ваш код написан под интерфейсы — Connection, Statement, ResultSet. Реальные классы, которые их реализуют, поставляются в драйвере-JAR поставщика. Задача JDBC — удержать ваш код на стороне интерфейсов этой границы, чтобы замена базы данных была изменением конфигурации, а не переписыванием.
Основные типы
Горстка интерфейсов встречается почти в каждой программе JDBC:
| Интерфейс | Роль |
|---|---|
DriverManager | Находит драйвер для вашего URL и возвращает Connection |
Connection | Активный сеанс с базой данных; фабрика для statements |
Statement | Отправляет фиксированную строку SQL |
PreparedStatement | Отправляет параметризованный SQL-шаблон (безопасный выбор по умолчанию) |
CallableStatement | Вызывает хранимую процедуру |
ResultSet | Курсор по строкам, которые вернул запрос |
SQLException | Проверяемое исключение, которое может бросить любой вызов JDBC |
Форма каждой программы JDBC
Почти весь доступ к данным следует одним и тем же пяти шагам. Вот они на примере активной базы данных, с использованием try-with-resources, чтобы каждый ресурс закрывал себя сам:
String url = "jdbc:postgresql://localhost:5432/shop";
String sql = "SELECT id, name FROM product WHERE price < ?";
try (Connection conn = DriverManager.getConnection(url, "app", "secret");
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setBigDecimal(1, new BigDecimal("9.99"));
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " " + rs.getString("name"));
}
}
}То есть: (1) назвать базу данных с помощью URL, (2) открыть Connection, (3) создать statement, (4) выполнить его, (5) прочитать ResultSet — а затем закрыть всё в обратном порядке. Остаток этой части разворачивает каждый шаг.
Независимая от поставщика система типов
Столбцы SQL — это не типы Java. JDBC соединяет их через константы java.sql.Types — VARCHAR, INTEGER, TIMESTAMP и так далее — и параллельный набор методов getXxx/setXxx. Вы редко боретесь с этим отображением, но именно оно является причиной того, что столбец DATE ходит туда-обратно как java.sql.Date, а NUMERIC — как BigDecimal.
Проработанный пример: входная дверь без установленного драйвера
Эта программа ни к чему не подключается — она исследует саму машинерию JDBC. Она спрашивает у DriverManager, какие драйверы зарегистрированы, показывает точный контракт, который вы получаете, когда ни один не соответствует URL, и печатает несколько констант типов, на которых построен API.
Что вынести из запуска:
getConnection— это единственная точка входа, и она опосредованаDriverManager. Вы никогда не создаёте соединение черезnew— вы называете базу данных с помощью URL, и JDBC маршрутизирует запрос. Среда выполнения здесь не имеет зарегистрированного драйвера, поэтому количество равно0.- Когда ни один драйвер не заявляет права на URL, JDBC не возвращает
nullи не зависает — он бросаетSQLExceptionс сообщением «No suitable driver found». Каждый метод JDBC сигнализирует об ошибке именно так, поэтомуSQLExceptionявляется проверяемым, и вы обрабатываете его повсюду. - Исключение несло SQLState (
08001, стандартный класс «client unable to establish connection»). Коды SQLState переносимы между поставщиками, в отличие от целочисленных кодов ошибок, которые специфичны для поставщика. - Константы
java.sql.Types— это обычныеint(VARCHARравно 12,INTEGERравно 4). С их помощью API называет типы SQL независимо от какой-либо одной базы данных, и вы будете передавать их вsetNullиregisterOutParameterв последующих главах. - Ничего из этого не требовало базы данных. API JDBC является частью JDK; внешним является только драйвер. Это разделение и есть весь замысел — ваш код компилируется и рассуждает о типах
java.sqlбез какой-либо базы данных в поле зрения.
Что охватывает остаток этой части
Загрузка и выбор драйверов, открытие и настройка Connection, три вида statements, навигация по ResultSet, транзакции, пакетные обновления и чтение метаданных базы данных. Следующая глава начинается там, где начинается каждое соединение: с драйвера.
Практика
В типичной программе JDBC почему код вашего приложения пишется под интерфейсы вроде Connection и ResultSet, а не под конкретные классы?