Топ-100Изоляция транзакций. Фантомное чтение - CodOrbits
LogoCodOrbits

Раздел: JDBC

Научитесь подключаться к базам данных через JDBC, выполнять SQL-запросы и обрабатывать результаты в Java.

Все разделы
Иконка JDBC

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

Last updated: 9 мая 2025 г.

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

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

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

1import java.sql.*;
2
3public class IsolationsPh {
4    public static void main(String[] args) 
5        throws ClassNotFoundException,
6        SQLException, InterruptedException {
7
8        //здесь идет транзакция А
9        Class.forName("com.mysql.cj.jdbc.Driver");
10        Connection connection = 
11            DriverManager.getConnection(
12            "jdbc:mysql://localhost/storage",
13            "root", "07998MSD");
14        Statement statement = 
15            connection.createStatement();
16        connection.setAutoCommit(false);
17        connection.setTransactionIsolation(
18            Connection.TRANSACTION_SERIALIZABLE);
19
20        //Видим два селект запроса ниже
21        //между которыми перерыв 2 секунды.
22        ResultSet resultSet = 
23            statement.executeQuery("SELECT * FROM books");
24        while (resultSet.next()) {
25            System.out.println("name: " 
26                + resultSet.getString("name"));
27        }
28
29        //Запускаем поток транзакции В
30        //В нем транзакция В должна добавить новую
31        //книгу в БД пока транзакция А остановлена.
32        new TransactionB().start();
33
34        //на две секунды останавливаем
35        //поток транзакции А, то есть текущий.
36        Thread.sleep(2000);
37
38        //Поток транзакции В в данный момент
39        //заблокирован поскольку транзакция А еще
40        //не выполнилась полностью.
41        //И когда нижний селект выполниться поток
42        //транзакции В разблокируется и только
43        //тогда новые данные появятся в БД.
44        //То есть очевидно транзакции А и В
45        //не пересекаются и не мешают друг другу.
46        ResultSet resultSet1 = 
47            statement.executeQuery("SELECT * FROM books");
48        while (resultSet1.next()) {
49            System.out.println("name: " 
50                + resultSet1.getString("name"));
51        }
52
53        //В случае с фантомным чтением еще
54        //нужно закоммитить чтобы поток В
55        //разблокировался.
56        connection.commit();
57    }
58    static class TransactionB extends Thread {
59        @Override
60        public void run() {
61            try {
62                Connection connection =
63                    DriverManager.getConnection(
64                    "jdbc:mysql://localhost/storage",
65                    "root", "07998MSD");
66                Statement statement =
67                    connection.createStatement();
68                connection.setAutoCommit(false);
69                connection.setTransactionIsolation(
70                    Connection.TRANSACTION_SERIALIZABLE);
71                //Пока идут 2 секунды в течении которых
72                //поток транзакции А остановлен
73                //транзакция В должна добавить новую
74                //книгу в БД, но она этого не сделает
75                //поскольку установлен режим
76                //TRANSACTION_SERIALIZABLE который
77                //блокирует поток транзакции В пока
78                //полностью не выполнится транзакция А.
79                //Видим ниже insert, а не update.
80                statement.executeUpdate("insert into "
81                    +"books (name, author) values "
82                    +"(‘new book’, ‘author of new book’)");
83                connection.commit();
84            } 
85            catch (SQLException e){}
86        }
87    }
88}

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

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

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


Следующие уроки

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

12
мин.

Similar Articles Icon
Divider

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

14
мин.

Similar Articles Icon
Divider

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

10
мин.

Similar Articles Icon