我的 MySQL 中有一个 InnoDB 表,每当产品售出时,它都会存储产品的当前库存(始终按单位,即始终为 -1) ,库存必须通过执行以下操作来更新:
UPDATE product_stock SET current_stock = current_stock -1 WHERE product_id = ?;
现在,我使用 Hibernate,因此我通过将 currentStock 属性的值设置为“currentValue -1”来更新对象 ProductStock,如下所示:
instance.setCurrentStock(instance.getCurrentStock()-1);
...
session.saveOrUpdate(instance);
现在,我正在使用事务来提交更改,但是我不确定当同时进行多次销售时 hibernate 会做什么,并且我无法成功复制我遇到的问题我认为会发生,即 current_stock 不会保存为 current_stock -1 ,而是保存为我设置给对象实例属性的值。 例如,我有 100 个,两个交易同时开始销售产品,并且都在代码中进行
instance.setCurrentStock(instance.getCurrentStock()-1);
将库存都设置为 99,然后交易结束,当前库存被保存为 99,而它应该是 98,对吗?
问题:我应该/必须创建一个 HQL 语句将库存直接更新为 -1,而不是从代码中更新对象的值吗?
更新:
我能够通过对许多用户同时购买的应用程序进行负载测试来复制错误,但实际发生的情况并不是 Hibernate 错误地保存了库存,而是发生了死锁 在数据库级别。我们目前正在努力解决这个问题,给出的答案非常有帮助。
我现在面临的问题是处理锁可能很棘手,因为 current_stock 表,特别是其中的某些行可能同时有许多读取和写入。我将发布进度并希望最终的解决方案
最佳答案
我认为你的选择是:
- 按照您的建议操作,并使用 HQL 直接减少数据库中的库存水平。这样做的缺点是,如果有多个同时交易,则无法保证库存水平不会低于零!
- 使用 Hibernate 的乐观或悲观锁定 - 文档中有很多关于此的信息 here .
- 确保数据库更新只能通过单个线程进行,这样事务就不会重叠。
关于java - 在 Hibernate 中将属性值减一,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20000424/