【问题标题】:Concurrency issue with WCF and nHibernateWCF 和 nHibernate 的并发问题
【发布时间】:2016-09-05 14:26:13
【问题描述】:

我们有一个处理一些业务实体的 WCF Web 服务。 ORM 是休眠 4.0.4、.NET 4.0。 我们使用 IDispatchMessageInspector 在 AfterReceiveRequest 中打开一个会话和一个事务,上下文类是 wcf_operation:

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
    if (!CurrentSessionContext.HasBind(this.factory))
    {
        this.log.Log.Debug("Creating NH Session");
        var session = this.factory.OpenSession();
        session.FlushMode = FlushMode.Never;
        session.BeginTransaction();
        CurrentSessionContext.Bind(session);
    }

    return null;
}

事务已提交,会话在 BeforeSendReply 中关闭。 只要一次只处理一个特定实体的调用,这就是有效的。

如果两个并发的 web 服务尝试更新同一个实体,我会得到一个休眠异常

NHibernate.HibernateException:非法尝试将集合与两个打开的会话关联

据我了解,两个更新在数据库级别发生冲突,我不明白 nhibernate 在这里遇到的问题。 根据我的理解,两个调用的两个会话应该是相互独立的;我在这里错过了什么吗?可能是配置?

如前所述,我看到了数据库存在的问题;尽管如此,我希望有一个例外声称有关并发更新的内容。 由于网络服务上的流量增加,我担心我的会话处理存在一般问题。

【问题讨论】:

  • 你能告诉我们BeforeSendReply方法吗?

标签: c# wcf nhibernate


【解决方案1】:

这个问题不是并发问题。问题是您使用 Session 的方式并非专为它们设计。

当一个实体对象从数据库加载时,它属于加载它的会话。会话保存它已加载的所有对象的内部映射。如果您尝试使该会话与由不同会话加载的对象进行交互,它将识别出该对象不在其内部映射中并引发异常。

请记住,会话遵循UnitOfWork 设计模式。它们注定是短暂的。您创建一个会话,从数据库中读取数据,进行更改,然后丢弃该会话以及所有内存中的对象。

NHibernate 确实提供了一种从会话中分离对象然后将其附加到不同会话的方法,但是这种方法在并发环境中会充满危险。相反,我建议您修改您的设计,使共享对象不是 nHibernate 实体,而是对该实体的某种键引用,这可以允许任何单独的会话在需要时重新加载它。

如果您认为某些对象确实应该在 WCF 服务的整个生命周期内都保留在内存中,您可以使用 nHibernate 二级缓存。 This blog entry 很好的解释了二级缓存。

【讨论】:

  • 这些对象在服务的生命周期内不在内存中,它们是每次调用的。如前所述,每个 wcf 调用都会创建一个新会话。当两个 Web 服务调用(每个都有自己的会话)尝试操作同一个实体(在我看来,它们应该是内存中的不同实体,因为它们来自不同的会话)时,我的问题就会出现
  • 为了更清楚一点,举个例子:假设我们有一个实体“Person”,它有一个名字、一个 ID 和一组地址。现在两个用户尝试更新同一个人,假设 id 为 1。我有两个并发调用我的 web 服务,都是为 id 为 1 的人。对于每个调用,都会创建一个新会话(见上文),获取该人从数据库,更新,人应该被保存。但随后抛出上述异常。
  • @Maroni - 此操作是否分散在多个 WCF 调用中?还是整个 fetch-update-save 操作都是一次调用完成的?
猜你喜欢
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
相关资源
最近更新 更多