java - 春季 JPA。更新数据库值的正确方法
问题描述
我正在学习 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
. 数据库中的值当然是错误的。你能解释什么是错的吗?谢谢!
解决方案
隔离级别 REPTEABLE_READ 按预期工作。
你可以在这里得到一个很好的解释:
但为了澄清,这就是发生的事情:
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
因此,为了控制这种行为,您有两种选择:
- 使用阻止操作的可序列化事务级别以便一一处理(这会降低性能)
- 实现乐观锁(第二个事务尝试同时修改同一个账户会抛出异常)
您可以在此处开始查看乐观锁定:JPA 中的乐观锁定如何工作?
推荐阅读
- javascript - 尝试在 vuejs 中重新渲染广告
- r - 使用 dplyr 和列中的一些条件创建一个新的数据框
- android - Nearby Connections API 的连接时间是否有下限?
- r - 当我尝试在 R 中安装 Mosaic 包时,这个错误是什么意思?
- ios - 在 Sirikit 中创建自定义类型参数
- swift - 如何将 Firebase 中的值添加到 xcode 中的标签?
- unity3d - 玩家和敌人之间的碰撞不再起作用,Unity2D
- javascript - 在VueJS中使用计算属性过滤结果时,如何在数组中显示所有文章?
- php - 来自服务器进程计时器的 Swoole 错误 9009 消息,而不是 Worker 进程回调?
- java - 如何使用模式和匹配器提取数据