wax*_*ing 8 java oracle deadlock jdbc
避免死锁的通常建议是始终以相同的顺序锁定资源.但是,对于高度满足的Oracle数据库中的行锁,您将如何实现这一点?
要了解我的意思,请考虑以下示例.一个非常简单的DAO来处理银行账户:
@Component
public class AccountDao {
@Resource
private DataSource dataSource;
public void withdraw(String account, int amount) {
modifyBalance(account, -amount);
}
public void deposit(String account, int amount) {
modifyBalance(account, amount);
}
private void modifyBalance(String account, int amount) {
try {
Connection connection = DataSourceUtils.getConnection(dataSource);
PreparedStatement statement = connection
.prepareStatement("update account set balance = balance + ? where holder = ?");
statement.setInt(1, amount);
statement.setString(2, account);
statement.execute();
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
要在两个帐户之间执行传输,有某种InternalBankTransfer类具有传输方法:
public void transfer(String from, String to, int amount) {
// start transaction
accountDao.withDraw(from, amount);
accountDao.deposit(to, amount);
// commit transaction
}
Run Code Online (Sandbox Code Playgroud)
通常这很好.但是,假设我们有两个人同时启动转账.让我们说安妮想要在鲍勃想要将50转移到安妮的同时向鲍勃转移100美元.所以在Anne调用的一个线程中transfer("Anne", "Bob", 100),以及另一个Bob调用transfer("Bob", "Anne", 50).如果执行顺序如下,则此代码容易受到死锁的影响:
T1: accountDao.withDraw("Anne", 100);
T2: accountDao.withDraw("Bob", 50);
T1: accountDao.deposit("Bob", 100);
T2: accountDao.deposit("Anne", 50); // BAM! ORA-00060: deadlock detected while waiting for resource
Run Code Online (Sandbox Code Playgroud)
我承认在我开始在真实应用程序中看到死锁之前我根本没有考虑过这个问题.我天真的看法是事务隔离类型自动处理这个问题.甲骨文表示,这是由于应用程序设计不佳造成的.但在这种情况下,什么是好的设计?我是否需要select for update我计划更新的所有内容?如果这是一个涉及更新几个表的巨大交易怎么办?我是否应该设计使死锁不可能或只是最小化并接受它们是生活中的事实?
我认为这是生活中的一个事实(而且应该只发生在高并发和热点数据的情况下)。
如果您想实现锁定顺序,那么是的,您需要重写代码以按预定顺序锁定或更新帐户(首先是 Anne,然后是 Bob)。但这对于复杂的交易来说是不可行的。如果它只发生在几个热点行上,也许您可以仅对这些热点行使用锁定顺序(并将其余部分保留原样)并继续下去。
或者使用粒度较小的锁,但这会杀死你的并发性。
对于您的情况,您只需重试已中止的事务即可。如果这种情况发生得太频繁,那么您的应用程序设计似乎确实存在问题。
以下是银行账户转账两阶段提交协议的链接。它来自 MongoDB wiki,即来自那些一开始就没有行锁和事务的人,但也可以在 RDBMS 上实现它以避免锁争用。这当然是一个相当激进的应用程序重新设计。我会先尝试其他一切(重试、粗略锁定、人为降低并发级别、批处理)。
| 归档时间: |
|
| 查看次数: |
6037 次 |
| 最近记录: |