2013-01-13 50 views
6

我使用查詢緩存設置NHibernate(使用NHibernate.LinqFluent NHibernate)。一切工作正常,直到我做了session.Save(new Widget())(即SQL INSERT)。在那之後,該類型Widget上的所有查詢都將錯過查詢緩存。其他實體類型的查詢緩存得很好。NHibernate - 在保存新實體後,查詢未命中查詢緩存

using (ISession session = MySessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction()) 
    { 
     // this INSERT screws things up 
     var widget = new Widget {Name = "Foo"}; 
     session.Save(widget); 

     var query = (from w in session.Query<Widget>().Cacheable() 
        where w.Name == "Bar" 
        select w); 

     var fetched1 = query.FirstOrDefault(); 
     var fetched2 = query.FirstOrDefault(); // miss?! 

     transaction.Commit(); 
    } 
} 

如果我開始一個新的Transaction,問題仍然存在。如果我開始新的Session,問題就會消失。這似乎有點奇怪,因爲我的理解是二級緩存根據SessionFactory(不是Session)重置。

我不認爲這很重要,但我使用的是HashtableCacheProvider,因爲我現在只是在測試。

+0

什麼樣的錯誤是發生爵士? – spajce

+0

從異常被拋出的意義上講,這不是一個錯誤。相反,第二個查詢('var fetched2 = query.FirstOrDefault();')跳過查詢緩存並直接訪問數據庫(這不是預期的行爲)。 –

+0

您是否啓用了查詢緩存?我認爲你必須從實體高速緩存中分離出來。 –

回答

6

您描述的行爲是正確的more here

直到您提交了 事務,更新時間戳緩存纔會更新!這是爲了確保您不會從緩存中讀取「未提交的 值」。

每當有一個type我們在緩存已經有了一個變化 - 緩存數據已過時......直到整個交易將提交。

試想一下,你這個緩存過濾器的結果:

var query = (from w in session.Query<Widget>().Cacheable() 
    where w.Name == "B*" // all names starting with B 
    select w); 

後來將增加新的Widget:

var widget = new Widget {Name = "Brigitte"}; 
session.Save(widget); 
// explicit Flush is not needed, 
// but then, until Commit(), query will never return Brigitte 
session.Flush(); // to immediately execute INSERT 

如果查詢將仍緩存,林青霞會不會出現..

而在Transaction中,使用FirstOrDefault()的查詢立即執行 - 寫入操作可能會等待Flush on Commit。

由於交易,所有包含的操作(插入,udpate,select)無法從緩存中獲益,因爲只有批次事務纔有意義。所以直到提交被調用,不能使用緩存。

許多詳細的和非常有益的信息可以在這裏找到:每當表將被寫入First and Second Level caching in NHibernate

時間戳緩存更新,但在棘手的方式排序:

  • 當我們執行實際的寫作,我們將寫入一個值在未來某處的緩存。因此,所有現在遇到 緩存的查詢都找不到它,然後點擊數據庫獲取新數據。 由於我們處於交易中,他們會等到我們 完成交易。如果我們使用的是低隔離級別,並且另一個線程/機器嘗試將舊結果放回 緩存中,它將不會成立,因爲更新時間戳將在 之後。
  • 當我們對事務執行提交時,我們用當前值更新時間戳緩存。