NHibernate的一級緩存,名詞好像很牛B,很難。實際上就是ISession緩存。存儲在ISession的運行周期內。而二級緩存則存儲在ISessionFactory內。
一、ISession一級緩存測試
ISession默認開啟一級緩存,不需要任何配置。ISession緩存在ISession創建后就可以使用,以后每次通過此ISession操作數據時,ISession會檢測自身是否緩存有相應的數據,如果有則直接返回。如果沒有,這時才查詢數據庫返回,同時緩存到ISession。當釋放ISession實例的時候,緩存自動銷毀。
示例:
首先我們先開啟配置文件中的show_sql節點:
<property name="show_sql">true</property> //開啟這個對本緩存測試沒影響,只是看看效果
PersonDao.cs
public class PersonDao { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); ISession session; public PersonDao() { session = sessionFactory.OpenSession(); }
public PersonModel GetPersonById(int Id) { PersonModel p = session.Get<PersonModel>(Id); return p; } }
Program.cs
class Program { static void Main(string[] args) { PersonDao dao = new PersonDao(); //第一次讀取 PersonModel p1 = dao.GetPersonById(3); Console.WriteLine(p1.Id + " " + p1.Name); //第二次讀取 PersonModel p2 = dao.GetPersonById(3); Console.WriteLine(p2.Id + " " + p2.Name); Console.ReadKey(); } }
輸出:
我們看到只有第一次查詢執行了SQL語句,第二次並沒有執行任何語句。這點從SQL Server Profiler中也可監控到。
在兩個會話中獲得同一實例
下面我們把
sessionFactory.OpenSession();
這行代碼放到方法里面會怎么樣呢?
public PersonModel GetPersonById(int Id) { ISession session = sessionFactory.OpenSession(); PersonModel p = session.Get<PersonModel>(Id); return p; }
輸出結果如下:
留意到每OpenSession一次,緩存就沒有了。OpenSession一次,NHibernate會自動釋放原有的ISession對象。
看到這里,你應該懂得注意下自己代碼的寫法了。
二、ISession.Get()與ISession.Load()的區別
不想廢話,十幾行代碼說明問題:
static void Main(string[] args) { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); ISession session = sessionFactory.OpenSession(); Console.WriteLine("Get之前"); PersonModel pGet = session.Get<PersonModel>(1); Console.WriteLine("Get之后"); Console.WriteLine("讀取名字" + pGet.Name); Console.WriteLine("====================================="); Console.WriteLine("Load之前"); PersonModel pLoad = session.Load<PersonModel>(2); Console.WriteLine("Load之后"); Console.WriteLine("讀取名字" + pLoad.Name); Console.ReadKey(); }
輸出結果如下:
留意到Get()執行的時候,就立即到數據庫讀取了。而Load()是延遲加載,到要用的時候,采取數據庫讀取,不用不讀。
不用Get<>或Load<>能否緩存
下面我們把PersonDao改成這樣:
public class PersonDao { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); ISession session; public PersonDao() { session = sessionFactory.OpenSession(); } public IList<PersonModel> GetPersonList() { return session.QueryOver<PersonModel>().List(); } }
Program.cs
static void Main(string[] args) { PersonDao dao = new PersonDao(); IList<PersonModel> PersonList1 = dao.GetPersonList(); Console.WriteLine(PersonList1[0].Name); IList<PersonModel> PersonList2 = dao.GetPersonList(); Console.WriteLine(PersonList1[0].Name); Console.ReadKey(); }
輸出:
留意到,還是執行了兩次SQL語句。看來,只有Get()或Load()才能使用NHibernate的一級緩存。
三、一級緩存的管理
當我們使用Get()或Load()的時候,不想使用一級緩存怎么辦呢?答案,使用
如我們回到本文的第一個示例,只改如下加粗的代碼:
public class PersonDao { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); IStatelessSession session; public PersonDao() { session = sessionFactory.OpenStatelessSession(); } public PersonModel GetPersonById(int Id) { PersonModel p = session.Get<PersonModel>(Id); return p; } }
Program.cs
static void Main(string[] args) { PersonDao dao = new PersonDao(); //第一次讀取 PersonModel p1 = dao.GetPersonById(3); Console.WriteLine(p1.Id + " " + p1.Name); //第二次讀取 PersonModel p2 = dao.GetPersonById(3); Console.WriteLine(p2.Id + " " + p2.Name); Console.ReadKey(); }
輸出結果如下:
可以看到NHibernate還是老老實實執行了兩次SQL語句。
NHibernate提供了如下三個方法,讓我們管理一級緩存。
- ISession.Evict(object):從緩存中刪除指定實例。
- ISession.Clear():清空緩存。
- ISession.Contains(object):檢查緩存中是否包含指定實例。
- ISession.Refresh(object):刷新緩存中的單個實例。
一個示例說明問題:
static void Main(string[] args) { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); ISession session = sessionFactory.OpenSession(); PersonModel p1 = session.Get<PersonModel>(1); PersonModel p2 = session.Get<PersonModel>(2); PersonModel p3 = new PersonModel(); Console.WriteLine(session.Contains(p1)); //輸出True Console.WriteLine(session.Contains(p2)); //輸出True session.Evict(p1); //從一級緩存中移除p1,看你還Con不Contains Console.WriteLine(session.Contains(p1)); //輸出False Console.WriteLine(session.Contains(p2)); //輸出True session.Clear(); //全部清空,看你還Con不Containsp2 Console.WriteLine(session.Contains(p2)); //輸出False Console.ReadKey(); }
輸出結果如下:
刷新緩存:
static void Main(string[] args) { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); ISession session = sessionFactory.OpenSession(); PersonModel p1 = session.Get<PersonModel>(1); Thread.Sleep(3000); Console.WriteLine("3秒鍾之后----------------"); session.Refresh(p1); Console.ReadKey(); }
輸出結果:
可以看到3秒鍾之后,NHibernate重新查詢了一次數據庫,獲得最新的對象。