问题描述
背景:在我的网络应用中,用户可以购买他们选择的商品。最近,我们发现一些用户因同一个项目列表而被多次收费。该问题可通过同时发送两个付款请求来重现。用户信息存储在 User
表中,每次用户付款尝试存储在 MS sql DB 中的 Payment
表中。 Payment
和 User
之间的关系是 Many To One
。
问题修复:为了解决这个问题,我添加了检查是否已经有一个记录来标识当前用户付款尝试正在进行中的逻辑。但是,在并发事务的情况下,当第二个事务对 SELECT
表执行 Payment
时,第一个事务可能不会插入记录,因此我必须暂停第二个事务,直到第一个事务插入新记录.
为了做到这一点,我在并发事务之间的共享资源上使用 JPA pessimistic write lock,它是 User
表中的记录。所以并发事务流程如下:
- 事务 1 从
User
表读取数据并在行上设置排他锁,以防止其他事务读取、更新或删除用户记录。生成的 sql select userdmo0_.Id as Id1_31_,... from dbo.User userdmo0_ with (updlock,holdlock,rowlock) where userdmo0_.Id=? - 事务 2 将无法获取锁,因此它将等待事务 1 释放自己的锁。
- 事务 1 使 INSERT... 插入
Payment
表,提交对数据库的更改并释放锁。 - 事务 2 锁定
User
表记录。 - 事务 2 检查是否有正在进行的付款。因为是,所以不会在
Payment
表中插入新记录。 - 事务 2 释放锁。
问题:修复工作正常。但是,我试图理解/预测的是应用程序性能影响。如果我能得到一些很好的解释就太好了,因为我找不到与性能方面相关的太多详细信息。
正如我在文档中读到的,当使用悲观锁时,在高并发的情况下,您可能会面临应用程序缓慢的问题,因为多个事务试图同时访问同一块数据。我不认为这是我的情况,我应该担心,因为白天只有十几个用户在 Payment
表中有单个重复记录,因此根本没有高并发。
但是在高负载情况下的应用,例如:100 个用户/秒付款。 MS sql 应该能够花费更多的资源来处理它创建的 100 个锁,对吗?此外,它是否会尝试将行锁升级为页锁或表锁?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)