Почему уровень изоляции "Repeatable read" в java спасает меня от "Phantom reads"?
Я написал код с фантомным чтением, и мой код должен печатать разные значения, если уровень изоляции не сериализуем, но у меня есть уровень изоляции "повторяемое чтение", и он работает как сериализуемый. Он показывает мне те же цифры, но должен второй раз показать большую цифру. Почему так? У меня есть база данных MySql. Вот мой пример:
public class PhantomReadLesson {
static String url = "jdbc:mysql://localhost:3306/Lessons";
static String username = "root";
static String password = "1";
public static void main(String[] args) throws SQLException, InterruptedException {
try(Connection conn = DriverManager.getConnection(url, username, password);
Statement statement = conn.createStatement()) {
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
ResultSet rs = statement.executeQuery("Select count(*) from Books");
while(rs.next()){
System.out.println(rs.getInt(1));
}
new OtherTransaction2().start();
Thread.currentThread().sleep(1000);
rs = statement.executeQuery("Select count(*) from Books");
while(rs.next()){
System.out.println(rs.getString(1));
}
}
}
static class OtherTransaction2 extends Thread {
@Override
public void run() {
try(Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement()) {
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
stmt.executeUpdate("insert into Books (name) VALUES ('new Row')");
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Я подражаю "фантомному чтению" здесь. Если я использую уровни 'repeatable_read' или 'serializable', он показывает те же цифры, если я использую уровни 'read_commmited' или 'read_uncomited', он показывает разные числа. Но в соответствии с документом java https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html сохраняются только сериализуемые данные из "фантомного чтения". Так зачем повторять сохранение уровня чтения из 'phanotom read'?
1 ответ
Из документов MySQL (о REPEATABLE READ
):
Последовательные чтения в одной и той же транзакции считывают моментальный снимок, созданный при первом чтении.
Операция чтения, которая использует информацию моментального снимка для представления результатов запроса на определенный момент времени, независимо от изменений, выполненных другими транзакциями, выполняющимися в то же время.
Как вы устанавливаете авто-коммит false
это означает, что оба выбора выполняются в одной транзакции. Итак, что вас беспокоит? Похоже, все работает так, как ожидалось.
Обратите внимание также на это замечание:
Предположим, что вы работаете с уровнем изоляции REPEATABLE READ по умолчанию. Когда вы выполняете согласованное чтение (то есть обычный оператор SELECT), InnoDB дает вашей транзакции момент времени, в соответствии с которым ваш запрос видит базу данных. Если другая транзакция удаляет строку и фиксирует ее после того, как был назначен ваш момент времени, вы не увидите строку как удаленную. Вставки и обновления обрабатываются аналогично.