Бесплатный курс по Java: от основ до продвинутого уровня
Изоляция транзакций в 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 консоль:
Как видим, оба селекта считали из БД четыре записи, то есть, очевидно, ничего еще в БД транзакция В не успела добавить пока транзакция А не завершилась.