NHibernate之一級緩存(第十篇)


  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重新查詢了一次數據庫,獲得最新的對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM