Nhibernate IList(有序列表)竞赛条件



想象一下这个场景:

  1. 实体上的有序集合
  2. 对集合中新项的两个同时(异步)CREATE请求
  3. 两个新项目得到相同的序号

收集是这样的:

public virtual IList<CustomField> CustomFields { get; protected set; }

我有流畅的nhibernate映射,如下所示:

mapping.HasManyToMany(cp => cp.CustomFields)
            .AsList(i => i.Column("CustomFieldOrdinal"))
            .ParentKeyColumn("RegistrationId")
            .ChildKeyColumn("CustomFieldId");

原因是nhibernate正在查询数据库以获取下一个可用的序号,而表上没有锁,并且两者都获得了相同的序号。

如何防止这种情况发生?

db中的唯一索引/约束可以处理这一问题。当然,对于这两个请求中的一个,您将不得不处理一个失败的flush。

如果您想避免在应用程序端处理异常,那么在读取(或从数据库刷新)其列表状态之前,您可以(或另外)对持有列表(ISession.Lock(entity, LockMode.Upgrade))的实体发出独占数据库锁。然后,更新列表
如果所有插入列表的应用程序都遵循相同的模式,那么它们将无法同时插入具有相同索引的元素:它们将等待锁释放,然后在读取并插入自己的新元素之前,将新数据保存在db中
这是一种悲观的并发模式。在这里也可以阅读更多信息(在另一个答案上可以找到链接)。

乐观的要求使用行版本列,并确保任何列表更新都与实体版本相接触。但是,在并发的情况下,对于两个请求中的一个,您将有一个并发异常。

我最终用Nhibernate的LockMode.Upgrade解决了这个问题。这很有效,解决了问题。

最新更新