Топ-100Изоляция транзакций. Неповторяющееся чтение - CodOrbits
LogoCodOrbits

Раздел: JDBC

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

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

Изоляция транзакций. Неповторяющееся чтение

Last updated: 9 мая 2025 г.

Допустим есть транзакция А и транзакция В в разных потоках.

Допустим в транзакции А есть несколько select запросов подряд.

Если транзакция В во время выполнения транзакции А изменит данные считываемые select-ами транзакции А, то это опять таки бывает не желательным.

Иногда нужно, чтобы сначала данные считались, то есть второй поток был заблокирован пока выполняется первый с транзакцией А, и данные обновились только после считывания всеми select-ами.

Для того чтобы изолировать транзакции от неповторяющегося чтения, нужно в обеих вызвать TRANSACTION_REPEATABLE_READ.

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

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

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

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

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


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

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

14
мин.

Similar Articles Icon
Divider

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

12
мин.

Similar Articles Icon
Divider

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

14
мин.

Similar Articles Icon