hibernate的查詢快取和二級快取的配合使用

weixin_34037977發表於2017-05-21

我的上一篇部落格Hibernate快取體系之查詢快取(query cache),以及list和iterate方法的差別介紹了查詢快取的概念,以及list和iterate的差別。讀者可能注意到:那篇部落格測試的前提是,僅僅開啟查詢快取,沒有開啟二級快取。

       通過各種情形測試,我們能夠得出一個結論:僅僅開啟查詢快取。不開啟二級快取是沒有意義的

為什麼這麼說呢?上一篇部落格能夠看出。不開啟二級快取,iterate()方法存在N+1次資料庫查詢問題,list方法最多僅僅能命中id。也須要N次資料庫查詢,不管是哪兒種情況,查詢快取已經失去了意義。這篇部落格我們開啟二級快取的情況下。將上篇部落格的情況再測試下。看下會是什麼效果。

hibernate4.1.6在hibernate.cfg.xml進行例如以下配置,能夠開啟二級快取。

<property name="cache.use_second_level_cache">true</property>
<property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>


因為測試程式碼和資料庫都和上篇部落格一模一樣。唯一不同就是開啟了二級快取。這裡不再附程式碼。直接通過測試結果來分析結論。


1. 2次list()執行結果分析

     testUseList()執行結果例如以下:

Hibernate: 
    select
        student0_.id as id0_,
        student0_.name as name0_,
        student0_.age as age0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
list語句測試query cache:hibernate.Student@d6c07[id=1, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@6279d[id=2, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@12dd76[id=3, name=zhangsan111, age=18]
-------list進行第二次查詢------
list語句測試query cache:hibernate.Student@1e6696c[id=1, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@135133[id=2, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@381d92[id=3, name=zhangsan111, age=18]
能夠發現list()第一次發出1條sql語句。第二次查詢沒有訪問資料庫,直接從快取中獲取的資料。在開啟查詢快取和二級快取的情況下,list將獲取到的id放入查詢快取,key是sql語句。將實體物件放入二級快取,key是實體物件的主鍵值。list會首先依據sql語句去查詢快取中獲取id,假設沒有獲取到則發出1條sql查詢語句,查詢出全部須要的欄位值。


2. 2次iterate()執行結果分析

     testUseIterator()執行結果例如以下:

<span style="font-size:14px;">Hibernate: 
    select
        student0_.id as col_0_0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@1f7cdc7[id=1, name=zhangsan111, age=18]
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@135133[id=2, name=zhangsan111, age=18]
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@1042fcc[id=3, name=zhangsan111, age=18]
-------iterate進行第二次查詢------
Hibernate: 
    select
        student0_.id as col_0_0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
iterate語句測試query cache:hibernate.Student@ad339b[id=1, name=zhangsan111, age=18]
iterate語句測試query cache:hibernate.Student@14c4d61[id=2, name=zhangsan111, age=18]
iterate語句測試query cache:hibernate.Student@6c5356[id=3, name=zhangsan111, age=18]</span>
第一次iterate()查詢,因為查詢快取和二級快取中都沒有資料,須要進行N+1次資料庫查詢;第二次查詢,僅僅發出一條sql查詢主鍵值,興許依據主鍵值從二級快取中獲取具體資訊。iterate方法會將獲取到的實體物件存入二級快取。至於是否會將id存入查詢快取,這裡還不能確定,只是能夠肯定的是。iterate不會利用查詢快取中的id值。而是每次查詢都又一次使用sql查詢滿足條件的記錄主鍵值。

之後再依據主鍵從二級快取中查詢實體物件。


3. 先iterate後list執行結果分析

     testIteratorAndList1()執行結果例如以下:

<span style="font-size:14px;">Hibernate: 
    select
        student0_.id as col_0_0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@58cca9[id=1, name=zhangsan111, age=18]
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@1042fcc[id=2, name=zhangsan111, age=18]
Hibernate: 
    select
        student0_.id as id0_0_,
        student0_.name as name0_0_,
        student0_.age as age0_0_ 
    from
        Student student0_ 
    where
        student0_.id=?
iterate語句測試query cache:hibernate.Student@38d460[id=3, name=zhangsan111, age=18]
-------第一次使用iterate,第二次使用list查詢------
Hibernate: 
    select
        student0_.id as id0_,
        student0_.name as name0_,
        student0_.age as age0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
list語句測試query cache:hibernate.Student@7efa96[id=1, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@75c78d[id=2, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@3acc67[id=3, name=zhangsan111, age=18]</span>
這裡能夠看出,iterate的快取資訊對於list是沒有幫助的。list會發出1條sql。從資料庫中查詢全部須要的欄位值。這裡能夠看出:iterate方法不會將主鍵值放到查詢快取中,由於假設放入查詢快取的話。這裡的list是沒有必要再發出sql查詢的。


4. 先listiterate執行結果分析

     testIteratorAndList2()執行結果例如以下:

<span style="font-size:14px;">Hibernate: 
    select
        student0_.id as id0_,
        student0_.name as name0_,
        student0_.age as age0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
list語句測試query cache:hibernate.Student@67c1a6[id=1, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@12f41a5[id=2, name=zhangsan111, age=18]
list語句測試query cache:hibernate.Student@17ebe66[id=3, name=zhangsan111, age=18]
-------第一次使用list,第二次使用iterate查詢------
Hibernate: 
    select
        student0_.id as col_0_0_ 
    from
        Student student0_ 
    where
        student0_.name='zhangsan111'
iterate語句測試query cache:hibernate.Student@feecca[id=1, name=zhangsan111, age=18]
iterate語句測試query cache:hibernate.Student@6bd9e0[id=2, name=zhangsan111, age=18]
iterate語句測試query cache:hibernate.Student@11710be[id=3, name=zhangsan111, age=18]</span>
這裡可以得出的結論,跟2次list()查詢幾乎相同。

唯一的區別是:iterate每次查詢都會發出查詢實體物件id的sql語句。



5. 總結

通過開啟查詢快取和二級快取,相同的sql查詢可以直接使用查詢快取中的id和二級快取中的實體物件,可以有效的降低反覆的資料庫查詢,可以提高查詢效率。也就是說:同一時候開啟查詢快取和二級快取是有意義的。也是實際使用hibernate的最佳配置。

進一步的。我們也能夠看出list和iterate方法的差別。list()會將實體物件的id放入查詢快取,將實體物件本身放入二級快取。iterate不會將實體物件的id放入查詢快取。可是會將實體物件本身存入二級快取。

假設第二次查詢可以命中的情況下:list全然不須要查詢資料庫,可以先從查詢快取中獲取到id。再從二級快取中獲取實體物件。iterate一定會發出一條查id的sql,然後去二級快取中獲取實體物件。

至此hibernate的二級快取、查詢快取的關係已經講完。list和iterate差別也已經測試出。

希望能對大家有幫助,假設錯誤。歡迎大牛們指正。


相關文章