首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >计算数据库死锁

计算数据库死锁
EN

Stack Overflow用户
提问于 2018-10-15 15:46:50
回答 2查看 111关注 0票数 0

我正在尝试编写一个springboot代码来更新基于借方/信用事务的钱包余额。我有两张桌子。 that transaction就是为了实现这一目标。我正在运行一个测试套件,它运行100个并行事务(50个借方和50个信用)。大约50%的事务失败,出现以下错误,而且钱包表中的钱包余额与存储在transaction表中的事务不匹配

尝试锁定时发现com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:死锁;尝试重新启动事务

我无法搞清楚:1)为什么死锁,2)为什么钱包余额与成功存储的事务数不匹配。我使用MySQL InnoDB作为数据库

代码语言:javascript
复制
@Transactional(isolation = Isolation.SERIALIZABLE)
  public Transaction saveTransaction(String walletId, Txn txn) {
    Optional<Wallet> byId = walletRepo.findById(Integer.parseInt(walletId));
    if (!byId.isPresent()) {
      throw new WalletNotFoundException();
    }
    Wallet wallet = byId.get();
    Transaction transaction = new Transaction();
    transaction.setAmount(txn.getAmount());
    transaction.setType(txn.getType());
    transaction.setWallet(wallet);
    BigDecimal balance = applyTransactionToWallet(txn, wallet.getBalance());
    Transaction save = transactionRepo.save(transaction);
    wallet.setBalance(balance);
    return save;
  }

  public Optional<Wallet> getWallet(String walletId) {
    Optional<Wallet> byId = walletRepo.findById(Integer.parseInt(walletId));
    return byId;
  }

  private BigDecimal applyTransactionToWallet(Txn txn, BigDecimal amount) {
    if (txn.getType() == TransactionType.CREDIT) {
      return amount.add(txn.getAmount());
    }
    return amount.subtract(txn.getAmount());
  }
EN

回答 2

Stack Overflow用户

发布于 2018-10-16 18:21:32

我在下面的行中使用findByIdInWriteMode而不是findById来修复死锁。

代码语言:javascript
复制
 Optional<Wallet> byId = walletRepo.findById(Integer.parseInt(walletId));

我把我的回购改为

代码语言:javascript
复制
@Repository
public interface WalletRepo extends JpaRepository<Wallet, Integer> {
  @Query(value = "FROM Wallet W where W.walletId = :id")
  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Optional<Wallet> findByIdInWriteMode(@Param("id") Integer id);
}
票数 0
EN

Stack Overflow用户

发布于 2018-10-16 18:46:35

如果您想要100%的即时一致性,您可以探索功能性锁定概念,其中您将把涉及到一个事务的钱包保存在一个功能锁定表中。因此,开始时的每个事务都会检查钱包上是否有任何功能性锁,如果是的话,等到它能够获得功能锁,否则插入到功能锁中,然后继续处理。在functional表中添加条目应该是原子的,并具有自己的commit。在事务结束时,删除锁定项。

如果您正在寻找最终的一致性(与延迟的一致性),您可以查看事务更新的队列,守护进程可以一个接一个地处理排队的项,再次使用函数锁定概念,以避免多个守护进程处理同一个钱包的事务。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52820374

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档