Изоляция транзакций в Java. Фантомное чтение

Фантомное чтение – по сути то же самое, что и неповторяющееся, только вместо update базы, будет insert в базу.

Для того чтобы изолировать транзакции от фантомного чтения, нужно в обеих вызвать TRANSACTION_SERIALIZABLE.

Пример программы:

import java.sql.*; public class IsolationsPh { public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { //здесь идет транзакция А Class.forName(“com.mysql.cj.jdbc.Driver”); Connection connection = DriverManager.getConnection( “jdbc:mysql://localhost/storage”, “root”, “07998MSD”); Statement statement = connection.createStatement(); connection.setAutoCommit(false); connection.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE); //Видим два селект запроса ниже //между которыми перерыв 2 секунды. ResultSet resultSet = statement.executeQuery(“SELECT * FROM books”); while (resultSet.next()) { System.out.println(“name: ” + resultSet.getString(“name”)); } //Запускаем поток транзакции В //В нем транзакция В должна добавить новую //книгу в БД пока транзакция А остановлена. new TransactionB().start(); //на две секунды останавливаем //поток транзакции А, то есть текущий. Thread.sleep(2000); //Поток транзакции В в данный момент //заблокирован поскольку транзакция А еще //не выполнилась полностью. //И когда нижний селект выполниться поток //транзакции В разблокируется и только //тогда новые данные появятся в БД. //То есть очевидно транзакции А и В //не пересекаются и не мешают друг другу. ResultSet resultSet1 = statement.executeQuery(“SELECT * FROM books”); while (resultSet1.next()) { System.out.println(“name: ” + resultSet1.getString(“name”)); } //В случае с фантомным чтением еще //нужно закоммитить чтобы поток В //разблокировался. connection.commit(); } static class TransactionB extends Thread { @Override public void run() { try { Connection connection = DriverManager.getConnection( “jdbc:mysql://localhost/storage”, “root”, “07998MSD”); Statement statement = connection.createStatement(); connection.setAutoCommit(false); connection.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE); //Пока идут 2 секунды в течении которых //поток транзакции А остановлен //транзакция В должна добавить новую //книгу в БД, но она этого не сделает //поскольку установлен режим //TRANSACTION_SERIALIZABLE который //блокирует поток транзакции В пока //полностью не выполнится транзакция А. //Видим ниже insert, а не update. statement.executeUpdate(“insert into ” +”books (name, author) values ” +”(‘new book’, ‘author of new book’)”); connection.commit(); } catch (SQLException e){} } } }

Скомпилируем, запустим программу:

Проверим таблицу books после завершения работы программы через MySQL консоль:

Как видим, оба селекта считали из БД четыре записи, то есть, очевидно, ничего еще в БД транзакция В не успела добавить пока транзакция А не завершилась.

Безопасные запросы с PreparedStatement

Узнайте, как PreparedStatement в JDBC защищает от SQL-инъекций. Примеры уязвимого кода и безопасной реализации для работы с базой данных в Java.
Time to read: 12

Использование хранимых процедур в Java

Как работать с хранимыми процедурами SQL в Java через JDBC: создание процедур, вызов через CallableStatement и обработка входных/выходных параметров.
Time to read: 14

Что такое HTML и зачем он нужен

HTML — язык разметки для создания структуры веб-страниц. Узнайте о базовых тегах (html, head, body, p) и их роли в верстке. Примеры простой разметки.
Time to read: 10