读取提交的隔离级别不起作用
Read Commited Isolation level not working
我正在尝试了解 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 和 睡眠 3 秒。
t2 启动,打开一个连接,读取余额并打印它(基本上是旧的,因为 t1 还没有提交) 然后关闭连接。
然后 t1 通过 提交 更新完成,程序结束。
我期望发生的事情是 t2 被阻塞,直到 t1 完成提交,因为 t2 正在访问同一银行帐户行(t1 应该锁定该行以进行更新)。因此,t2 应该打印了银行账户 #490 的更新余额,而不是之前的。
为什么 t1 不锁定该行?为什么 t2 没有被屏蔽?
请注意,隔离级别 设置为 TRANSACTION_READ_COMMITTED
。
t2 中的 select 语句没有被阻塞,因为它只是试图读取而不是写入。如果您要尝试执行更新(或 select...for update),那么如果您的超时设置为在放弃之前等待一段时间,它可能会阻塞。您没有提到您使用的是哪个数据库,但这里有一些关于 Postgres 如何处理锁定的不错的文档:
https://www.postgresql.org/docs/current/explicit-locking.html
我正在尝试了解 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 和 睡眠 3 秒。
t2 启动,打开一个连接,读取余额并打印它(基本上是旧的,因为 t1 还没有提交) 然后关闭连接。
然后 t1 通过 提交 更新完成,程序结束。
我期望发生的事情是 t2 被阻塞,直到 t1 完成提交,因为 t2 正在访问同一银行帐户行(t1 应该锁定该行以进行更新)。因此,t2 应该打印了银行账户 #490 的更新余额,而不是之前的。
为什么 t1 不锁定该行?为什么 t2 没有被屏蔽?
请注意,隔离级别 设置为 TRANSACTION_READ_COMMITTED
。
t2 中的 select 语句没有被阻塞,因为它只是试图读取而不是写入。如果您要尝试执行更新(或 select...for update),那么如果您的超时设置为在放弃之前等待一段时间,它可能会阻塞。您没有提到您使用的是哪个数据库,但这里有一些关于 Postgres 如何处理锁定的不错的文档: https://www.postgresql.org/docs/current/explicit-locking.html