2016-05-10 76 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調用中嗎?或者這整個抓取更新保存操作是否都作爲一個調用完成? –