如何在 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 中实现一致的事务?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中实现 ORM

如何在sqlite django ORM中实现have子句

如何在LibGDX中实现Sugar ORM

在 WP7 中实现回滚事务

如何在 ETl 中实现零停机

如何在 vb.net 中实现交易方式?