如何在 ORM 中实现一致的事务?
Posted
技术标签:
【中文标题】如何在 ORM 中实现一致的事务?【英文标题】:How to achieve consistent transactions in ORMs? 【发布时间】:2019-10-16 10:53:44 【问题描述】:我的问题是概念性的。
假设我们使用 ORM(如 Entity Framework、Hibernate 等)并在这些 ORM 中建模我们的领域对象。既然 ORM 会为我们抽象出大部分 SQL/do 事务,那么我们如何确保我们的事务是一致的呢?
示例: 我们有一个卖书的网上商店。如果我们卖一本书,我们基本上会使用类似这样的东西:
var book = books.Single(b => b.Id == 42);
book.Quantity -= 1;
books.SaveChanges();
但如果我正确理解 ORM,它们只会将 book 的更改包装在 UPDATE 查询中。这意味着您可能会遇到这样的基本并发问题: concurrency issue with orms
如果您要使用 SQL,您只需将 .Quantity -= 1 包装在事务中并保证安全。
您通常会如何在 ORM 中以适当的方式处理这个问题,或者这会以某种方式自动处理?
【问题讨论】:
【参考方案1】:在更改数量之前,您必须选择更新。这将锁定记录。
这取决于您使用的 ORM。使用 Hibernate,您可以在查询时设置 LockModeType。
在 Hibernate 中,这将是 LockModeType.PESSIMISTIC_WRITE
阅读 Hibernate 文档中有关锁定的更多信息:
https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#locking
【讨论】:
好吧,如果更新查询只是最后的增量,我不应该使用 select 进行更新。既然一个更新语句是原子的,就不能丢失更新吗?或者你的意思是如果不锁定“通常”的 ORM 就不可能做到这一点? 更新语句是原子的,但这意味着您必须发出更新语句,而不是使用 orm 选择数据,然后使用 orm 进行更改和持久化数据。选择和更新之间会有时间【参考方案2】:Entity Framework 为此使用Optimistic Concurrency。并且大多数 RDBMS 系统不会使用事务来防止这种更新异常。
UPDATE T SET Quantity = Quantity - 1 WHERE ID = :ID
这个单一语句将自动运行,虽然使用单一语句可以防止丢失更新,但它不能保证 Quantity 不会减少到零以下。
悲观锁不仅需要事务,还需要锁定提示或提升的事务隔离级别。
【讨论】:
如果我错了,请纠正我,但更高的事务隔离级别不会阻止这些异常,因为事务不会干扰。但我仍然不明白如何在 EF 中做到这一点。使用数量作为并发令牌会产生很多 DbUpdateConcurrencyExceptions,这不是问题吗? 事务和更高的隔离级别将防止异常,但可能会通过生成异常或死锁来实现。乐观并发总是通过创建异常来防止丢失更新。以上是关于如何在 ORM 中实现一致的事务?的主要内容,如果未能解决你的问题,请参考以下文章