Бесплатный курс по Java: от основ до продвинутого уровня
Изоляция транзакций в Java. Неповторяющееся чтение
Допустим есть транзакция А и транзакция В в разных потоках.
Допустим в транзакции А есть несколько select запросов подряд.
Если транзакция В во время выполнения транзакции А изменит данные считываемые select-ами транзакции А, то это опять таки бывает не желательным.
Иногда нужно, чтобы сначала данные считались, то есть второй поток был заблокирован пока выполняется первый с транзакциейА, и данные обновились только после считывания всеми select-ами.
Для того чтобы изолировать транзакции от неповторяющегося чтения, нужно в обеих вызвать TRANSACTION_REPEATABLE_READ.
Пример программы:
import java.sql.*;
public class IsolationsRep {
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”, “0799MSD”);
Statement statement = connection.createStatement();
connection.setAutoCommit(false);
//изолируем транзакцию от неповторяющегося чтения
connection.setTransactionIsolation(
Connection.TRANSACTION_REPEATABLE_READ);
//Выпим два селекта запроса ниже
//между которыми перерыв 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”));
}
}
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_REPEATABLE_READ);
//Пока идут 2 секунды в течении которых
//поток транзакции А остановлен
//транзакция В должна обновить данные
//второй книги, но она этого не сделает
//поскольку установлен режим
//TRANSACTION_REPEATABLE_READ, который
//блокирует поток транзакции В пока
//полностью не выполнится транзакция А.
statement.executeUpdate(“update books set”
+” name = ‘another name’ where id = 2″);
connection.commit();
}
catch (SQLException e){}
}
}
}
Скомпилируем, запустим программу:
Проверим таблицу books после завершения работы программы через MySQL консоль:
Как видим, оба селекта считали из БД одни и те же данные. То есть пока транзакция А не завершилась транзакция В не влияла на БД и соответственно на то, что считывала транзакция А.