У нас есть простой счетчик в нашей базе данных проекта. До сих пор мы использовали версию базы данных H2 1.4.197. Выполнение приведенного ниже примера фрагмента с этой версией всегда подразумевает, что счетчик равен 5000. Обновление до версии 1.4.198 или выше приводит к тому, что код ниже возвращает противоречивые результаты, обычно между 1500 и 2000.
public static void main(String[] args) throws SQLException, InterruptedException {
String url = "jdbc:h2:mem:testdb";
Connection connection = DriverManager.getConnection(url);
connection.prepareStatement("CREATE TABLE t1 (id INT PRIMARY KEY, counter INT)").execute();
connection.prepareStatement("INSERT INTO t1 (id, counter) VALUES (1, 0)").execute();
int threads = 10;
int times = 500;
ExecutorService service = Executors.newFixedThreadPool(threads);
ExecutorCompletionService<Void> cs = new ExecutorCompletionService<>(service);
for (int i = 0; i < threads; i++) {
cs.submit(() -> {
Connection conn = DriverManager.getConnection(url);
IntStream.range(0, times).forEach($ -> {
try {
conn.prepareStatement("UPDATE t1 SET counter = (SELECT counter FROM t1 WHERE id = 1) + 1 WHERE id = 1").executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
});
return null;
});
}
for (int i = 0; i < threads; i++) {
cs.take();
}
ResultSet resultSet = connection.prepareStatement("SELECT counter FROM t1 WHERE id = 1").executeQuery();
resultSet.next();
System.out.println("counter: " + resultSet.getInt("counter"));
}
Я предполагаю, что выбор Оператор снизу SQL выполняется перед блокировкой освобождения другой транзакции из таблицы, а затем выполняется обновление с использованием устаревших данных из оператора выбора.
"UPDATE t1 SET counter = (SELECT counter FROM t1 WHERE id = 1) + 1 WHERE id = 1"
У кого-нибудь была похожая проблема?