【问题标题】:Spring JPA. The right way to update database values春季 JPA。更新数据库值的正确方法
【发布时间】:2019-03-02 07:37:06
【问题描述】:

我正在学习 Spring JPA 和 Hibernate。所以我遇到了一个问题。

我有这个方法

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void sendMoney(Long from, Long to, Double amount) {
    WalletEntity fromWallet = walletServiceImpl.getWallet(from);
    WalletEntity toWallet = walletServiceImpl.getWallet(to);
    fromWallet.setAmount(fromWallet.getAmount() - amount);
    toWallet.setAmount(toWallet.getAmount() + amount);

    TransactionEntity transaction = new TransactionEntity();
    transaction.setAmount(amount);
    transaction.setToWallet(toWallet);
    transaction.setFromWallet(fromWallet);

    transactionRepository.saveAndFlush(transaction);
}

我想测试它并创建了这个:

@GetMapping("/send")
public void sendMoney() {
    ExecutorService executorService = Executors.newFixedThreadPool(20);
    for (int i = 0; i < 100; i++) {
        executorService.execute(() -> {
            accountServiceImpl.sendMoney(1L, 2L, 10D);
        });
    }
}

所以当我阅读钱包时,我得到了旧值,但我做了Isolation.REPEATABLE_READ。数据库中的值当然是错误的。 你能解释什么是错的吗?谢谢!

【问题讨论】:

  • 数据库值错误是什么意思?
  • 我执行了 100 次,从钱包 1 到钱包 2 拿了 10 个“钱”。我期望钱包 1 的价值少 1000,钱包 2 的价值多 1000。但是少了大约 200-300 个。
  • 改用“Isolation.READ_COMMITTED”

标签: java database spring spring-data-jpa isolation-level


【解决方案1】:

隔离级别 REPTEABLE_READ 按预期工作。

你可以在这里得到一个很好的解释:

Spring @Transactional - isolation, propagation

但为了澄清,这就是发生的事情:

                      Tx1      Tx2
                       |        |
Tx1 Read Wallet 1     100       |
Tx2 Read Wallet 1      |       100
Tx1 Discounts 10     100-10     |
Tx2 Discounts 10       |      100-10
Tx1 Commits            |        |
Tx2 Commits            |        |
Tx1 Read Wallet 1      90       |
Tx2 Read Wallet 2      |        90

因此,为了控制这种行为,您有两种选择:

  1. 使用阻止操作的可序列化事务级别以便逐一处理(这会降低性能)
  2. 实现乐观锁(第二个事务同时修改同一个账户会抛出异常)

您可以在此处开始查看乐观锁定:Optimistic locking in JPA how does it work?

【讨论】:

  • 我尝试使用可序列化级别,但由于死锁而失败Deadlock found when trying to get lock; try restarting transaction
  • 检查这个答案:stackoverflow.com/questions/17747906/…。但是我相信你必须处理乐观锁定(你必须避免同时对钱包进行两次修改)。
猜你喜欢
  • 2018-07-31
  • 2016-01-30
  • 2013-11-12
  • 2019-01-10
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多