Spring MVC和Hibernate中的事务处理

3
我正在使用Spring MVC 3.0和Hibernate。我的情况是这样的,我有一个库存,用户可以添加和删除物品。例如,总数量=50。现在两个用户同时想要更新库存,比如A删除2个物品,B删除4个物品。因此,总数量=44。那么,当两个用户同时尝试更新库存时,我该如何处理这个事务?如果不维护事务,那么它将变成50-2=48,然后50-4=46。
2个回答

2

-1

您可以使用带版本控制的乐观锁定。 只需将 或 属性添加到持久类映射中,即可启用带版本控制的乐观锁定。 在 XML 中,属性映射必须紧随标识符属性映射之后:

<class name="Item" table="ITEM">
    <id .../>
    <version name="version" access="field" column="OBJ_VERSION"/>
     ...
</class>

有了这个,当项目更新时,SQL 将会是:

update ITEM set INITIAL_PRICE='12.99', OBJ_VERSION=2
where ITEM_ID=123 and OBJ_VERSION=1

如果另一个并发工作单元更新并提交了相同的行,则OBJ_VERSION列不再包含值1,该行也不会被更新。Hibernate通过JDBC驱动程序返回的语句行数(在本例中为零)检查此语句的行数,并抛出StaleObjectStateException异常。

如果您没有版本或时间戳列,Hibernate仍然可以执行自动版本控制,但仅适用于在相同持久性上下文(即相同会话)中检索和修改的对象。版本控制的这种替代实现将当前数据库状态与检索对象时(或最后一次刷新持久性上下文时)的未修改持久属性的值进行比较。您可以通过设置类映射上的optimistic-lock属性来启用此功能:

<class name="Item" table="ITEM" optimistic-lock="all">
<id .../>
...
</class>

现在执行以下SQL来刷新Item实例的修改: update ITEM set ITEM_PRICE='12.99' where ITEM_ID=123 and ITEM_PRICE='9.99' and ITEM_DESCRIPTION="An Item" and ... and SELLER_ID=45

在这两种情况下,你需要重新启动第二个事务或合并更新,以解决StaleObjectStateException。这种情况应该很少见,否则,你需要重构以减少事务范围,使其更小、更快。

你可以参考CHRISTIAN BAUER和GAVIN KING的《Java Persistent with Hibernate》一书获取更多细节。(推荐)

编辑:Ryan是正确的。我更正了我的答案。


1
这也是不正确的。Hibernate 默认采用乐观锁定,因此它不会“只是起作用”。 - Ryan Stewart
@ Ryan Stewart 你说的“optimistic locking”是什么意思?可以解释一下吗? - curiouss
我搜索了乐观锁并发控制相关内容,得出以下结果:乐观锁总是假设一切都会顺利进行,冲突的数据修改是罕见的。在乐观并发控制中,仅在写入数据时的工作单元末尾才会引发错误。多用户应用程序通常默认使用乐观并发控制和具有读提交隔离级别的数据库连接。只在适当的情况下才会获得其他隔离保证,例如需要可重复读取时。 这种方法保证了最佳的性能和可伸缩性。 - Jacky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接