Wikipedia describes the Phantom reading phenomenon as:
A Phantom reading occurs when two identical queries are executed during a transaction, and the set of rows returned by the second query is different from the first.
It also states that with a serialized isolation level, Phantom reading is not possible. I'm trying to make sure that this is the case in H2, but I expect something is wrong, or I'm wrong, or something is wrong with H2. However, here is the code:
try(Connection connection1 = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { connection1.setAutoCommit(false); try(Connection connection2 = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { connection2.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); connection2.setAutoCommit(false); assertEquals(0, selectAll(connection1)); assertEquals(0, selectAll(connection2));
Here I launch 2 simultaneous connections and configure one of them to serializable transaction isolation. After that, I make sure that both do not see any data. Then, using connection1 , I insert a new line. After that, I make sure that this new line is visible for connection1 , but not for connection2 . Then I commit the change and expect connection2 not be aware of this change. In short, I expect all my A: select queries to return the same set of rows (an empty set in my case).
But this does not happen: the last selectAll(connection2) returns the string that was just inserted into the parallel connection. Am I mistaken, and is this behavior expected, or is it something wrong with H2?
Here are the helper methods:
public void setUpDatabase() 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(); } }
Full test here: https://gist.github.com/loki2302/26f3c052f7e73fd22604
I am using H2 1.4.185.