Я пытаюсь провести несколько тестов, чтобы понять, как можно использовать уровни изоляции транзакций для решения различных проблем параллелизма. Я начал с TRANSACTION_READ_COMMITED
, но самый простой сценарий ведет себя не так, как я ожидал. Вот код:
try(Connection connection1 = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
connection1.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
connection1.setAutoCommit(false);
try(Connection connection2 = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
connection2.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
connection2.setAutoCommit(false);
assertEquals(0, selectAll(connection1));
assertEquals(0, selectAll(connection2));
insertOne(connection1);
assertEquals(0, selectAll(connection2)); // there is 1 row!
}
}
Здесь я устанавливаю 2 одновременных соединения, запускаю транзакцию в них обоих, вношу изменения в первое соединение и ожидаю, что не увижу их во втором. Это не работает: незафиксированные изменения, сделанные в соединении 1, видны для соединения 2.
Я использую HSQLDB 2.3.2, работающую во встроенном режиме с базой данных в памяти. Вот реализации моих вспомогательных методов selectAll/insert:
private static void initSchema() throws SQLException {
try(Connection connection = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
try (PreparedStatement s = connection.prepareStatement(
"create table Notes(text varchar(256) not null)")) {
s.executeUpdate();
}
}
}
private static int selectAll(Connection connection) throws SQLException {
int count = 0;
try (PreparedStatement s = connection.prepareStatement("select * from Notes")) {
s.setQueryTimeout(1);
try (ResultSet resultSet = s.executeQuery()) {
while (resultSet.next()) {
++count;
}
}
}
return count;
}
private static void insertOne(Connection connection) throws SQLException {
try(PreparedStatement s = connection.prepareStatement("insert into Notes(text) values(?)")) {
s.setString(1, "hello");
s.setQueryTimeout(1);
s.executeUpdate();
}
}
Полный тест можно найти здесь: https://gist.github.com/loki2302/aad49a5a2c26d5fda2b3.
Что-то не так с этим кодом или HSQLDB ведет себя не так, как должен?
Обновление: перечитав вики, я считаю, что моя идея неверна. То, что я вижу здесь, является «фантомным чтением». READ_COMMITTED
не гарантирует, что фантомное чтение никогда не произойдет. Вместо этого я должен проверить предварительное распространение таблицы с одной строкой, обновление ее через connection1
и убедиться, что это изменение не видно через connection2
, если только изменение не зафиксировано. Более того, вообще не гарантируется, что это изменение станет видимым сразу после коммита: оно может стать видимым, но не гарантируется.