WCF和nHibernate的并发问题

时间:2016-05-10 14:26:52

标签: c# wcf nhibernate

我们有一个WCF Web服务处理一些业务实体。 ORM是nhibernate 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中关闭会话。 只要一次只有一个呼叫处理特定实体,这就有效。

如果两个并发的webservice尝试更新同一个实体,我会得到一个nhibernate异常

  

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

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

如上所述,我看到了数据库存在的问题;尽管如此,我希望有一个例外声明有关conccurent更新的事情。 由于Web服务上的流量增长,我担心我的会话处理存在一般性问题。

1 个答案:

答案 0 :(得分:1)

此问题不是并发问题。问题是您正在以不适合的方式使用Sessions。

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

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

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

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