Введение в Java JDBC
Что такое JDBC, как он абстрагирует доступ к базе данных в Java и архитектура JDBC API.
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 | Активный сеанс с базой данных; фабрика для операторов |
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) создайте оператор, (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в последующих главах. - Здесь не потребовалась база данных. JDBC API является частью JDK; только драйвер является внешним компонентом. В этом разделении и состоит весь замысел — ваш код компилируется и работает с типами
java.sqlбез какой-либо базы данных в поле зрения.
Когда использовать JDBC
JDBC — это фундамент, на котором стоит каждый высокоуровневый инструмент для работы с данными в Java. Объектно-реляционные маперы вроде Hibernate или JPA, построители запросов вроде jOOQ и более лёгкие вспомогательные средства вроде Spring's JdbcTemplate — все они вызывают JDBC под капотом. Используйте JDBC напрямую, когда вам нужен полный контроль над SQL, минимальный объём зависимостей или когда вы изучаете, как этот слой работает на самом деле. Используйте ORM, когда предпочитаете сопоставлять строки с объектами и избегать шаблонного кода. В любом случае концепции этого раздела — соединения, операторы, результирующие наборы и транзакции — это именно то, чем управляют те инструменты за вас.
Что охватывает остаток этого раздела
Загрузка и выбор драйверов, открытие и настройка Connection, три вида операторов (Statement, PreparedStatement и CallableStatement), а также навигация по ResultSet, плюс транзакции, пакетные обновления и чтение метаданных базы данных. Следующая глава начинается там, где начинается каждое соединение: с драйвера.