【发布时间】:2020-08-18 01:21:01
【问题描述】:
我正在尝试了解 ACID 隔离原则。我已经编写了这部分代码:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Runnable t2 = () -> {
System.out.println("Thread: " + Thread.currentThread().getName());
Connection connection;
try {
connection = this.iDatabaseConnector.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM mssmbank.mssmbank.bankaccounts WHERE id = ?");
preparedStatement.setInt(1, 490);
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.next();
System.out.println("Result: " + resultSet.getDouble("BALANCE"));
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
};
Runnable t1 = () -> {
System.out.println("Thread: " + Thread.currentThread().getName());
Connection connection;
try {
connection = this.iDatabaseConnector.getConnection();
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
connection.setAutoCommit(false);
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE mssmbank.mssmbank.bankaccounts " + "SET balance = ? WHERE id = ?");
preparedStatement.setDouble(1, (new Random()).nextInt(1000));
preparedStatement.setInt(2, 490);
preparedStatement.executeUpdate();
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
executorService1.execute(t2);
Thread.sleep(3_000);
connection.commit();
connection.close();
executorService1.shutdown();
executorService1.awaitTermination(20, TimeUnit.SECONDS);
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
};
executorService.execute(t1);
executorService.shutdown();
executorService.awaitTermination(20, TimeUnit.SECONDS);
有 2 个线程,t1 和 t2。 t1 应该更新数据库中的银行帐户行,t2 应该读取其余额。
以下是场景:t1 启动、打开连接、进行更新并且不提交。它会触发 t2 和 sleeps 3 秒。
t2 启动,打开连接,读取余额并打印(基本上是旧的,因为 t1 尚未提交)然后关闭连接。
然后t1通过提交更新结束,程序结束。
我期望发生的是,t2 被阻止,直到 t1 完成提交,因为 t2 正在访问同一个银行帐户行(t1 应该已锁定该行以进行更新)。因此,t2 应该打印了 #490 银行账户的更新余额,而不是之前的余额。
为什么t1 不锁定行?为什么 t2 没有被阻止?
请注意,隔离级别设置为TRANSACTION_READ_COMMITTED。
【问题讨论】:
-
这不是事务读取提交的工作方式。 t2 获取先前提交的值,即先前的值。这就是为什么您通常会快速更新和提交,以最小化另一个事务可以读取旧的、先前提交的值的窗口。
-
谢谢,这很清楚。所以这不是关于脏读的场景吗?
标签: java multithreading postgresql jdbc isolation-level