NHibernate 事务和竞争条件

Posted

技术标签:

【中文标题】NHibernate 事务和竞争条件【英文标题】:NHibernate transaction and race condition 【发布时间】:2008-09-23 08:08:22 【问题描述】:

我有一个 ASP.NET 应用程序,它使用 NHibernate 在用户操作时以事务方式更新一些表。涉及一个日期范围,因此只能在“预订”表中输入一个条目,以便指定排他日期。

我的问题是如何防止竞争条件,即两个用户操作几乎同时发生并导致多个条目进入“预订”>1 日期。我无法在调用 .Commit() 之前进行检查,因为我认为这仍然会导致竞争条件?

我所能看到的只是在提交后进行检查并手动回滚更改,但这让我的嘴巴感觉很糟糕! :)

booking_ref (INT) PRIMARY_KEY AUTOINCREMENT

booking_start (DATETIME)

booking_end (DATETIME)

【问题讨论】:

【参考方案1】: 使事务的隔离级别 SERIALIZABLE (session.BeginTransaction(IsolationLevel.Serializable) 并检查并插入同一个事务。一般情况下,您不应该将隔离级别设置为可序列化,只是在这种情况下。

在检查并最终插入之前锁定表。您可以通过 nhibernate 触发 SQL 查询来做到这一点:

session.CreateSQLQuery("SELECT null as dummy FROM Booking WITH (tablockx, holdlock)").AddScalar("dummy", NHibernateUtil.Int32); 这将在该事务期间仅锁定该表以进行选择/插入。

希望对你有帮助

【讨论】:

当然——不敢相信我竟然完全错过了使用表锁,当时脑子一片空白!非常感谢。【参考方案2】:

以上解决方案可以作为一个选项使用。如果我在事务级别可序列化时使用“Parallel.For”发送了 100 个请求,是的,没有重复的请求 ID,但 25 个事务失败。我的客户不能接受。所以我们解决了这个问题,只存储请求 id 并在其他表上添加一个唯一索引作为临时表。

【讨论】:

【参考方案3】:

您的数据库应该管理您的数据完整性。

您可以使您的“日期”列独一无二。因此,如果 2 个线程尝试获取相同的日期。一个会抛出唯一的密钥违规,另一个会成功。

【讨论】:

以上是关于NHibernate 事务和竞争条件的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate学习教程--事务Transactions

事务如何在 nhibernate 中工作?

NHibernate之并发控制简记

在每个请求使用会话时如何让 NHibernate 重试死锁事务?

在Sharp Architecture中使用NHibernate处理嵌套事务

NHibernate Oracle - 事务提交问题