Для чего нужен drivermanager jdbc
Перейти к содержимому

Для чего нужен drivermanager jdbc

  • автор:

Простой пример JDBC для начинающих

Здравствуйте! В этой статье я напишу простой пример соединения с базами данных на Java.Эта статья предназначена новичкам.Здесь я опишу каждую строчку объясню что зачем.

Но для начала немного теории.

JDBC (Java DataBase Connectivity — соединение с базами данных на Java) предназначен для взаимодействия Java-приложения с различными системами управления базами данных (СУБД). Всё движение в JDBC основано на драйверах которые указываются специально описанным URL.

А теперь практика.

Для начала создаём maven проект и в pom.xml помещаем зависимость для соединения с СУБД (В моём случае СУБД будет выступать MySQL):

   mysql mysql-connector-java 5.1.38   

Должно получится так:

Дальше подключаемся к базе данных нужной вам(я пользуюсь IDEA Ultimate по этому я подключаюсь именно так).

Дальше заполняем Database, User и Password.Обязательно проверяем соединение.

Дальше мы создаём сам класс.

А теперь разберём его построчно:

В начале мы создаём три переменные url,username и password. Образец указания url:

Username по умолчанию root.Password вы должны знать сами.

После с помощью строчки Class.forName(«com.mysql.jdbc.Driver») регестрируем драйвера. Дальше устанавливаем соединение с помощью DriverManager.getConnection (ваш url, username, password).

После с помощью connection (соединения) создаём простой запрос Statement методом createStatement().

Дальше создаём экземпляр класса ResultSet и формируем запрос через statement методом executeQuery (запрос).

Дальше мы заставляем пробежаться resultSet по всей базе данных и вывести то что нам нужно. Так с помощью объекта resultSet и его методов (getString,getInt и т.д. в зависимости от типа переменных в колонке) мы выводим.Так как мой запрос был для того что бы вывести всё, мы можем вывести любую колонку.

После закрываем resultSet,statement и connection (именно в такой последовательности). В процессе он будет показывать ошибки так как будет запрашивать обработку исключений в catch.Так что пишите catch заранее.

Теперь когда практика есть на неё можно наложить более глубокую теорию.Тема правда очень большая, желаю удачи в её изучении.

Этот проект на github тут.

Зачем нужен Driver при подключении к базе данных?

Здравствуйте.
Я начал изучать базы данных в Java, нашел много разных статей, уроков. Многие вводят экземпляр класса com.mysql.cj.jbdc.Driver и регистрируют его в DriverManager, после чего он не применяется, кто-то регистрирует его через Class.forName(«com.mysql.jdbc.Driver»).newInstance(), кто-то не прописывет его вообще, однако CRUD запросы это выполнять не мешает.
Собственно, вопрос: нужен ли этот самый драйвер, если все запросы выполняются, и если да, то зачем?

  • Вопрос задан более трёх лет назад
  • 2487 просмотров

2 комментария

Простой 2 комментария

Beshere

В Java 8 JDBC уже вырезали, так что, наверно, придется «изучать базы данных в Java» заново.
ivan19631224 @ivan19631224

В Java 8 JDBC уже вырезали, так что, наверно, придется «изучать базы данных в Java» заново.

Что за ерунда, ничего не вырезали, всё как было, так и есть: Java JDBC API. Более того и в девятке и в десятке всё остаётся, даже новые версии API выходят. Другое дело, что появляются всякие разные слои абстракции типа JPA, JDO, Hibernate и т.п., и, возможно, более правильно изучать что-то из этого. Но все они всё равно базируются на JDBC, и рано или поздно всё равно нужно будет с этим разбираться.

Решения вопроса 0
Ответы на вопрос 2
ivan19631224 @ivan19631224

Технически это происходит обычно так. Когда вы вызываете Class.forName(«. «) , JVM подгружает этот класс и вызывает статический инициализатор этого класса. В случае с JDBC драйверами они, как правило, там вызывают статический метод DriverManager.registerDriver(. ) и регистрируют сами себя (пример для mysql). Регистрация представляет собой просто сохранение во внутреннем статическом списке. Далее, когда вы вызываете DriverManager.getConnection(jdbcUrl) , DriverManager по этой jdbcUrl ищет подходящий драйвер (дёргая метод acceptsURL , который должны реализовывать все драйверы), далее подключается с помощью метода connect этого драйвера. Конечно, есть ещё много нюансов, особенно если касаться web приложений.
Чтобы вызывали Class.forName(«. «).newInstance() я не видел, это вроде ничем не отличается от просто new com.mysql.jdbc.Driver() .
Собственно, ответ на вопрос: да, конечно нужен. Драйвер реализует общение приложения с базой данных (т.е. передачу SQL запросов в БД и возврат результатов), без него никак. Если вы не видите, что класс драйвера и его настройки прописаны явно, скорее всего где то во внутренностях кода/ресурсов они всё таки есть.

Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
кто знает, тот поймет

Слово драйвер («водитель») в первую очередь означает элемент который будет направлять ваши запросы к базе данных и возвращать вам ответы. К множеству баз данных свой драйвер, поэтому его и надо означить. Собственно как и в других языках код не обращается напрямую к драйверу, драйвер в данном случае выступает как константа определяющая вид запроса на более низком уровне.

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

android

  • Android
  • +2 ещё

Почему при сворачивание приложения оно не развёртывается?

  • 1 подписчик
  • 15 часов назад
  • 34 просмотра

JDBC

JDBC — это платформенно независимый промышленный стандарт взаимодействия Java-приложений с реляционными базами данных. Впервые был включен в состав JDK 1.1 в 1997 году. JDBC управляет:

Освойте профессию «Java-разработчик»

  • подключением к базе данных;
  • выдачей запросов и команд;
  • обработкой данных, полученных из базы.

Как работает JDBC

Пакет JDBC состоит из двух главных компонентов:

  1. API (программного интерфейса), который поддерживает связь между Java-приложением и менеджером JDBC;
  2. Драйвера JDBC, который поддерживает связь между менеджером JDBC и драйвером базы данных.

Профессия / 14 месяцев
Java-разработчик

Освойте востребованный язык

Group 1321314345 (4)

Соединение с базой устанавливается по особому URL. При этом разработчику не нужно знать специфику конкретной базы — API выступает в качестве посредника между базой и приложением. Это упрощает как процесс создания приложения, так и переход на базу данных другого типа.

Этапы подключения к базе данных

  1. Установка базы данных на сервер или выбор облачного сервиса, к которому нужно получить доступ.
  2. Подключение библиотеки JDBC.
  3. Проверка факта нахождения необходимого драйвера JDBC в classpath.
  4. Установление соединения с базой данных с помощью библиотеки JDBC.
  5. Использование установленного соединения для выполнения команд SQL.
  6. Закрытие соединения после окончания сеанса.

Рассмотрим каждый из этих шагов подробнее.

Установка SQLite

СУБД (система управления базами данных) SQLite отличается компактными размерами и простотой установки — для ее использования не нужна инсталляция дополнительных сервисов. Вся информация хранится в одном файле формата .db, который нужно поместить в папку с программой. Учебную базу можно скачать здесь.

Станьте Java-разработчиком
и создавайте сложные сервисы
на востребованном языке

Импорт JDBC в Java-приложение

Для использования JDBC, как и в случае со всеми остальными приложениями на платформе Java, в системе должен быть установлен JDK. Код для работы с JDBC можно писать как в среде разработки (IDE), так и в обычном текстовом редакторе. Простейшая программа может выглядеть так:

class WhatIsJdbcpublic static void main(String args[])System.out.println(«Hello World»);
>
>

Скомпилируйте этот код с помощью команды:

javac WhatIsJdbc.java

Теперь, когда программа готова, можно импортировать библиотеки JDBC. Для этого вставьте данный ниже код перед строками программы «Hello, World»:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;

Каждый из импортированных модулей предоставляет доступ к классам, которые необходимы для взаимодействия Java-приложения с базой данных:

  1. Connection подготавливает подключение к базе.
  2. DriverManager обеспечивает подключение. Другая опция — модуль DataSource.
  3. SQLException обрабатывает SQL-ошибки, возникающие при взаимодействии приложении и базы данных.
  4. ResultSet и Statement моделируют наборы результатов данных и операторы SQL.

Добавление JDBC-драйвера в classpath

JDBC-драйвер — это класс, обеспечивающий взаимодействие интерфейса JDBC API с базой данных определенного типа. Драйвер для SQLite представляет собой .jar-файл — его нужно добавить в classpath, как показано ниже:

java.exe -classpath /path-to-driver/sqlite-jdbc-3.23.1.jar:. WhatIsJdbc

Установление соединения с базой данных

Теперь в classpath есть доступ к драйверу. Вставьте приведенный ниже код в файл с вашей первой программой:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;
class WhatIsJdbcpublic static void main(String[] args) Connection conn = null;
try String url = «jdbc:sqlite:path-to-db/chinook/chinook.db»;
conn = DriverManager.getConnection(url);
System.out.println(«Соединение установлено»);
> catch (SQLException e) throw new Error(«Ошибка при подключении к базе данных», e);
> finally try if (conn != null) conn.close();
>
> catch (SQLException ex) System.out.println(ex.getMessage());
>
>
>

Теперь можно компилировать и запускать код. В случае успешного подключения появится сообщение «Соединение установлено».

Создание запроса к базе данных

В приведенном ниже примере показано, как создать запрос к базе SQLite, используя Connection и Statement:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;
class WhatIsJdbcpublic static void main(String[] args) Connection conn = null;
try String url = «jdbc:sqlite:path-to-db-file/chinook/chinook.db»;
conn = DriverManager.getConnection(url);
Statement stmt = null;
String query = «select * from albums»;
try stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) String name = rs.getString(«title»);
System.out.println(name);
>
> catch (SQLException e ) throw new Error(«Problem», e);
> finally if (stmt != null) < stmt.close(); >
>
> catch (SQLException e) throw new Error(«Problem», e);
> finally try if (conn != null) conn.close();
>
> catch (SQLException ex) System.out.println(ex.getMessage());
>
>
>

Результатом выполнения этого кода будет вывод списка музыкальных альбомов из учебной базы в консоль.

Возможностей JDBC API достаточно для реализации простых приложений. Для более масштабных решений чаще используют JPA API, который позволяет сохранять Java-объекты в базе данных.

Java-разработчик

Java уже 20 лет в мировом топе языков программирования. На нем создают сложные финансовые сервисы, стриминги и маркетплейсы. Освойте технологии, которые нужны для backend-разработки, за 14 месяцев.

картинка (67)

Статьи по теме:

JDBC или с чего всё начинается

Java-университет

В современном мире без хранения данных никак. И история работы с базами данных началась уже очень давно, с появления JDBC. Предлагаю вспомнить то, без чего не обходися ни один современный фрэймворк, построенный поверх JDBC. Кроме того, даже работая с ними временами может понадобится возможность «вернуться к корням». Надеюсь, обзор поможет как вступительное слово или поможет что-то освежить в памяти.

JDBC или с чего всё начинается - 1

Вступление

Одна из основных целей языка программирования — хранение и обработка информации. Чтобы лучше понять работу хранения данных стоит немного времени выделить на теорию и архитектуру приложений. Например, можно ознакомиться с литературой, а именно с книгой «Software Architect’s Handbook: Become a successful software architect by implementing effective arch. » авторства Joseph Ingeno. Как сказано, есть некий Data Tier или «Слой данных». Он включает в себя место хранения данных (например, SQL базу данных) и средства для работы с хранилищем данных (например, JDBC, о котором и пойдёт речь). Так же на сайте Microsoft есть статья: «Проектирование уровня сохраняемости инфраструктуры» в которой описывается архитектурное решение выделения из Data Tier дополнительного слоя — Persistence Layer. В таком случае Data Tier — это уровень хранения самих данных, в то время как Persistence Layer — это некоторый уровень абстракции для работы с данными из хранилища с уровня Data Tier. К уровню Persistence Layer можно отнести шаблон «DAO» или различные ORM. Но ORM — это тема отдельного разговора. Как Вы могли уже понять, вначале появился Data Tier. Ещё с времён JDK 1.1 в Java мире появился JDBC (Java DataBase Connectivity — соединение с базами данных на Java). Это стандарт взаимодействия Java-приложений с различными СУБД, реализованный в виде пакетов java.sql и javax.sql, входящих в состав Java SE:

JDBC или с чего всё начинается - 2

Данный стандарт описан специфкицией «JSR 221 JDBC 4.1 API». Данная спецификация рассказывает нам о том, что JDBC API предоставляет программный доступ к реляционным базам данных из программ, написанных на Java. Так же рассказывает о том, что JDBC API является частью платформы Java и входит поэтому в Java SE и Java EE. JDBC API представлен двумя пакетами: java.sql and javax.sql. Давайте тогда с ними и познакомимся.

JDBC или с чего всё начинается - 3

Начало работы

Чтобы понять что такое вообще JDBC API нам понадобится Java приложение. Удобнее всего воспользоваться одной из систем сборки проектов. Например, воспользуемся Gradle. Более подробно про Gradle можно прочитать в небольшом обзоре: «Краткое знакомство с Gradle». Для начала инициализируем новый Gradle проект. Так как функциональность Gradle реализуется через плагины, то для инициализации нам нужно воспользоваться «Gradle Build Init Plugin»:

 gradle init --type java-application 

Откроем после этого билд скрипт — файл build.gradle, где описывается наш проект и то, как с ним нужно работать. Нас интересует блок «dependencies«, где описываются зависимости — то есть те библиотеки/фрэймворки/api, без которых мы не можем работать и от которых мы зависим. По умолчанию мы увидим что-то вроде:

 dependencies < // This dependency is found on compile classpath of this component and consumers. implementation 'com.google.guava:guava:26.0-jre' // Use JUnit test framework testImplementation 'junit:junit:4.12' >

Почему мы тут это видим? Это зависимости нашего проекта, которые нам сгенерировал автоматически Gradle при создании проекта. А так же потому что guava — это отдельная библиотека, не входящая в комплект с Java SE. JUnit так же не входит в комплект с Java SE. Но JDBC у нас есть «из коробки», то есть входит в состав Java SE. Получается JDBC у нас есть. Отлично. Что же нам ещё надо? Есть такая замечательная схема:

JDBC или с чего всё начинается - 4

Как мы видим, и это логично, база данных является внешним компонентом, которого нет изначально в Java SE. Это объясняется просто — существует огромное количество баз данных и работать вы можете захотеть с любой. Например, есть PostgreSQL, Oracle, MySQL, H2. Каждая из этих баз данных поставляется отдельной компанией, которые называются поставщиками баз данных или database vendors. Каждая база данных написана на каком-то своём языке программирования (не обязательно Java). Чтобы с базой данных можно было работать из Java приложения поставщик базы данных пишет особый драйвер, который является своего образа адаптером. Такие JDBC совместимые (то есть у которых есть JDBC драйвер) ещё называют «JDBC-Compliant Database». Тут можно провести аналогию с компьютерными устройствами. Например, в блокноте есть кнопка «Печать». Каждый раз когда вы её нажимаете программа сообщает операционной системе, что приложение блокнот хочет напечатать. И у Вас есть принтер. Чтобы научить разговаривать единообразно вашу операционную систему с принтером Canon или HP понадобятся разные драйверы. Но для Вас, как пользователя, ничего не изменится. Вы по прежнему будете нажимать одну и ту же кнопку. Так и с JDBC. Вы выполняете один и тот же код, просто «под капотом» могут работать разные базы данных. Думаю, тут очень понятный подход. Каждый такой JDBC драйвер — это некоторый артефакт, библиотека, jar файл. Он то и является зависимостью для нашего проекта. Например, мы можем выбрать базу данных «H2 Database» и тогда нам надо добавить зависимость следующим образом:

 dependencies < implementation 'com.h2database:h2:1.4.197' 

То, как найти зависимость и как её описать указано на официальных сайтах поставщика БД или на "Maven Central". JDBC драйвер не является базой данных, как Вы поняли. А лишь является проводником к ней. Но есть такое понятие, как "In memory databases". Это такие базы данных, которые существуют в памяти на время жизни вашего приложения. Обычно, это часто используют для тестирования или для учебных целей. Это позволяет не ставить отдельный сервер баз данных на машине. Что нам очень даже подойдёт для знакомств с JDBC. Вот и готова наша песочница и мы приступаем.

JDBC или с чего всё начинается - 5

Connection

  • Через DriverManager
  • Через DataSource
 Connection con = DriverManager.getConnection(url, user, passwd); 

Параметры можно взять с сайта выбранной нами базы данных. В нашем случае это H2 — "H2 Cheat Sheet". Перейдём в подготовленный Gradle'ом класс AppTest. Он содержит JUnit тесты. JUnit тест — это метод, который помечен аннотацией @Test . Юнит тесты не являются темой данного обзора, поэтому просто ограничимся пониманием того, что это описанные определённым образом методы, цель которых что-то протестировать. Согласно специфкиации JDBC и сайту H2 проверим, что мы получили подключение к БД. Напишем метод получения подключения:

 private Connection getNewConnection() throws SQLException

Теперь напишем тест для этого метода, который проверит, что подключение действительно устанавливается:

 @Test public void shouldGetJdbcConnection() throws SQLException < try(Connection connection = getNewConnection()) < assertTrue(connection.isValid(1)); assertFalse(connection.isClosed()); >> 

Данный тест при выполнении проверит, что полученное подключение валидное (корректно созданное) и что оно не закрыто. Благодаря использованию конструкции try-with-resources мы освободим ресурсы после того, как они нам больше не нужны. Это убережёт нас от "провисших" соединений и утечек памяти. Так как любые действия с БД требуют подключения, то давайте для остальных тестовых методов, помеченных @Test, обеспечим в начале теста Connection, который мы освободим после теста. Для этого нам понадобится две аннотации: @Before и @After Добавим в класс AppTest новое поле, которое будет хранить JDBC подключение для тестов:

 private static Connection connection; 

И добавим новые методы:

 @Before public void init() throws SQLException < connection = getNewConnection(); >@After public void close() throws SQLException

Теперь, любому тестовому методу гарантируется наличие JDBC connection и он не должен каждый раз сам его создавать.

JDBC или с чего всё начинается - 6

Statements

  • Statement: SQL выражение, которое не содержит параметров
  • PreparedStatement : Подготовленное SQL выражение, содержащее входные параметры
  • CallableStatement : SQL выражение с возможностью получить возвращаемое значение из хранимых процедур (SQL Stored Procedures).
 private int executeUpdate(String query) throws SQLException < Statement statement = connection.createStatement(); // Для Insert, Update, Delete int result = statement.executeUpdate(query); return result; >

Добавим метод создания тестовой таблицы с использованием прошлого метода:

 private void createCustomerTable() throws SQLException

Теперь протестируем это:

 @Test public void shouldCreateCustomerTable() throws SQLException

Теперь давайте выполним запрос, да ещё и с параметром:

 @Test public void shouldSelectData() throws SQLException

JDBC не поддерживает именованные параметры для PreparedStatement, поэтому сами параметры указываются вопросами, а указывая значение мы указываем индекс вопроса (начиная с 1, а не с нуля). В последнем тесте мы получили true как признак того, есть ли результат. Но как представлен результат запроса в JDBC API? А представлен он как ResultSet.

JDBC или с чего всё начинается - 7

ResultSet

Понятие ResultSet описано в спецификации JDBC API в главе "CHAPTER 15 Result Sets". Прежде всего, там сказано, что ResultSet предоставляет методы для получения и манипуляции результатами выполненных запросов. То есть если метод execute вернул нам true, значит мы можем получить и ResultSet. Давайте вынесем вызов метода createCustomerTable() в метод init, который отмечен как @Before. Теперь доработаем наш тест shouldSelectData:

 @Test public void shouldSelectData() throws SQLException < String query = "SELECT * FROM customers WHERE name = ?"; PreparedStatement statement = connection.prepareStatement(query); statement.setString(1, "Brian"); boolean hasResult = statement.execute(); assertTrue(hasResult); // Обработаем результат ResultSet resultSet = statement.getResultSet(); resultSet.next(); int age = resultSet.getInt("age"); assertEquals(33, age); >

Тут стоит отметить, что next — это метод, который двигает так называемый "курсор". Курсор в ResultSet указывает на некоторую строку. Таким образом, чтобы считать строку, на неё нужно этот самый курсор установить. Когда курсор перемещается, то метод перемещения курсора возвращает true, если курсор валидный (правильный, корректный), то есть указывает на данные. Если возвращает false, значит данных нет, то есть курсор не указывает на данные. Если попытаться получить данные с невалидным курсором, то мы получим ошибку: No data is available Ещё интересно, что через ResultSet можно обновлять или даже вставлять строки:

 @Test public void shouldInsertInResultSet() throws SQLException

RowSet

JDBC помимо ResultSet вводит такое понятие, как RowSet. Подробнее можно прочитать здесь: "JDBC Basics: Using RowSet Objects". Существуют различные вариации использования. Например, самый простой случай может выглядеть так:

 @Test public void shouldUseRowSet() throws SQLException

Как видно, RowSet похож на симбиоз statement (мы указали через него command) и выполнили command. Через него же мы управляем курсором (вызывая метод next) и из него же получаем данные. Интересен не только такой подход, но и возможные реализации. Например, CachedRowSet. Он является "отключённым" (то есть не использует постоянное подключение к БД) и требует явного выполнения синхронизации с БД:

 CachedRowSet jdbcRsCached = new CachedRowSetImpl(); jdbcRsCached.acceptChanges(connection); 

Подробнее можно прочитать в tutorial на сайте Oracle: "Using CachedRowSetObjects".

JDBC или с чего всё начинается - 8

Metadata

Кроме запросов, подключение к БД (т.е. экземпляр класса Connection) предоставляет доступ к метаданным - данным о том, как настроена и как устроена наша база данных. Но для начала озвучим несколько ключевых моментов: URL подключения к нашей БД: "jdbc:h2:mem:test". test - это название нашей базы данных. Для JDBC API это каталог. И название будет в верхнем регистре, то есть TEST. Схема по умолчанию (Default schema) для H2 - PUBLIC. Теперь, напишем тест, который показывает все пользовательские таблицы. Почему пользовательские? Потому что в базах данных есть не только пользовательские (те, которые мы сами создали при помощи create table выражений), но и системные таблицы. Они необходимы, чтобы хранить системную информацию о структуре БД. У каждой БД такие системные таблицы могут храниться по-разному. Например, в H2 они хранятся в схеме "INFORMATION_SCHEMA". Интересно, что INFORMATION SCHEMA является общим подходом, но Oracle пошли иным путём. Подробнее можно прочитать здесь: "INFORMATION_SCHEMA и Oracle". Напишем тест, получающий метаданные по пользовательским таблицам:

 @Test public void shoudGetMetadata() throws SQLException < // У нас URL = "jdbc:h2:mem:test", где test - название БД // Название БД = catalog DatabaseMetaData metaData = connection.getMetaData(); ResultSet result = metaData.getTables("TEST", "PUBLIC", "%", null); Listtables = new ArrayList<>(); while(result.next()) < tables.add(result.getString(2) + "." + result.getString(3)); >assertTrue(tables.contains("PUBLIC.CUSTOMERS")); > 

JDBC или с чего всё начинается - 9

Пул подключений

Пулу подключений в спецификации JDBC отведен раздел "Chapter 11 Connection Pooling". В нём же и даётся главное обоснование необходимости пула подключений. Каждый Coonection - это физическое подключение к БД. Его создание и закрытие - довольно "дорогая" работа. JDBC предоставляет лишь API для пула соединений. Поэтому, выбор реализации остаётся за нами. Например, к таким реализациям относится HikariCP. Соответственно, нам понадобится добавить пул к нам в зависимости проекта:

 dependencies

Теперь надо как-то пул этот задействовать. Для этого нужно выполнить инициализацию источника данных, он же Datasource:

 private DataSource getDatasource()

И напишем тест на получение подключения из пула:

 @Test public void shouldGetConnectionFromDataSource() throws SQLException < DataSource datasource = getDatasource(); try (Connection con = datasource.getConnection()) < assertTrue(con.isValid(1)); >> 

JDBC или с чего всё начинается - 10

Транзакции

  • Data Manipulation Language, он же DML (Insert, Update, Delete)
    Транзакция завершается как только завершилось выполнение действия Select Statements
    Транзакция завершается тогда, когда ResultSet будет закрыт (ResultSet#close)
  • CallableStatement и выражения, возвращающие несколько результатов
    Когда все ассоциированные ResultSets будут закрыты и все выходные данные получены (включая кол-во апдейтов)
 @Test public void shouldCommitTransaction() throws SQLException < connection.setAutoCommit(false); String query = "INSERT INTO customers VALUES (1, 'Max', 20)"; connection.createStatement().executeUpdate(query); connection.commit(); Statement statement = connection.createStatement(); statement.execute("SELECT * FROM customers"); ResultSet resultSet = statement.getResultSet(); int count = 0; while(resultSet.next()) < count++; >assertEquals(2, count); > 

Всё просто. Но это так, пока у нас всего одна транзакция. А что делать, когда их несколько? Нужно их изолировать друг от друга. Поэтому, поговорим об уровнях изоляции транзакции и как с ними справляется JDBC.

JDBC или с чего всё начинается - 11

Уровни изоляции

  • Atomicity(Атомарность):
    Никакая транзакция не будет зафиксирована в системе частично. Будут либо выполнены все её подоперации, либо не выполнено ни одной.
  • Consistency(Согласованность):
    Каждая успешная транзакция по определению фиксирует только допустимые результаты.
  • Isolation(Изолированность):
    Во время выполнения транзакции параллельные транзакции не должны оказывать влияния на её результат.
  • Durability(Долговечность):
    Если транзакция успешно завершенеа, сделанные в ней изменения не будут отменены из-за какого-либо сбоя.

Далее, используем это в версиях:

 dependencies < implementation "com.h2database:h2:$" implementation "com.zaxxer:HikariCP:$" testImplementation "junit:junit:$" > 

Вы могли заметить, что версия h2 стала ниже. Позже мы увидим, зачем. Итак, как же применять уровни изолированности? Давайте посмотрим сразу небольшой практический пример:

 @Test public void shouldGetReadUncommited() throws SQLException < Connection first = getNewConnection(); assertTrue(first.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); first.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); first.setAutoCommit(false); // Транзакиця на подключение. Поэтому первая транзакция с ReadUncommited вносит изменения String insertQuery = "INSERT INTO customers VALUES (5, 'Max', 15)"; first.createStatement().executeUpdate(insertQuery); // Вторая транзакция пытается их увидеть int rowCount = 0; JdbcRowSet jdbcRs = new JdbcRowSetImpl(getNewConnection()); jdbcRs.setCommand("SELECT * FROM customers"); jdbcRs.execute(); while (jdbcRs.next()) < rowCount++; >assertEquals(2, rowCount); > 

Интересно, что данный тест может упасть на вендоре, который не поддерживает TRANSACTION_READ_UNCOMMITTED (например, sqlite или HSQL). А ещё уровень транзакции может просто не сработать. Помните мы указывали версию драйвера H2 Database? Если мы поднимем её до h2Version = '1.4.177' и выше, то READ UNCOMMITTED перестанет работать, хотя код мы не меняли. Это ещё раз доказывает, что выбор вендора и версии драйвера - это не просто буквы, от этого будет в реальности зависеть то, как будут выполняться ваши запросы. Про то, как исправить это поведение в версии 1.4.177 и как это не работает в версиях выше можно прочитать здесь: "Support READ UNCOMMITTED isolation level in MVStore mode".

Итог

  • Огненный доклад: "Transactions: myths, surprises and opportunities" от Martin Kleppmann
  • Юрий Ткач: "JPA. Транзакции"
  • Юрик Ткач: "JDBC - Java для тестировщиков"
  • Бесплатный курс на Udemy: "JDBC and MySQL"
  • "Обработка объектов CallableStatement"
  • IBM Developer: "Java Database Connectivity"
  • IBM Knowledge Center: "Getting started with JDBC"

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *