2016-05-10 75 views
2

我们有一个WCF web服务处理一些业务实体。 ORM是nhibernate 4.0.4,.NET 4.0。 我们使用的是IDispatchMessageInspector打开一个会话,并在AfterReceiveRequest交易,上下文类是wcf_operation:WCF和nHibernate并发问题

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的异常

NHibernate.HibernateException:非法尝试集合有两个打开的会话

据我了解,联想两个更新在数据库级别发生冲突,我不明白这里有nhibernate的问题。 从我的理解来看,两次电话会议应该是相互独立的;我在这里错过了什么吗?一个配置可能?

如上所述,我看到数据库存在的问题;不过,我希望有一个例外声明关于concaturent更新的内容。 由于Web服务的流量增长,我担心我的会话处理存在一般性问题。

+0

你能告诉我们'BeforeSendReply'方法吗? –

回答

1

此问题不是并发问题。问题在于你正在以一种他们没有设计的方式使用会话。

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

请记住,会话遵循UnitOfWork设计模式。他们的目的是短暂的。您可以创建一个会话,从数据库读取数据,进行更改,然后丢弃会话以及所有内存中的对象。 NHibernate的确提供了一种方法来从会话中分离一个对象,然后将它附加到不同的会话中,但是这种方法在并发环境中会充满危险。相反,我建议你修改你的设计,以便共享对象不是一个nHibernate实体,而是某种对实体的键引用,如果需要,它可以允许任何单独的会话重新加载它。

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

+0

这些对象在服务的整个生命周期内都不在内存中,它们是每次调用的。如上所述,每个wcf调用都会创建一个新的会话。我的问题发生在两个web服务调用(每个都有一个自己的会话)试图操纵同一个实体时(在我看来,这应该是内存中的不同实体,因为它们来自不同的会话) – Maroni

+0

为了使它更清晰一些, :可以说我们有一个实体“Person”,其中包含aname,一个id和一组地址。现在两个用户尝试更新同一个人,让我们说ID 1。我有两个并发呼叫到我的web服务,无论是身份证1的人。对于每次调用,创建一个新的会话(见上文),该人从数据库中获取,进行更新,应该保存人员。但是上面提到的例外是抛出的。 – Maroni

+0

@Maroni - 这个动作分散在多个WCF调用中吗?或者这整个抓取更新保存操作是否都作为一个调用完成? –