1. 程式人生 > >Hibernate快取原理與查詢快取的組合探究

Hibernate快取原理與查詢快取的組合探究

來源:http://www.javaeye.com/topic/431603

0.前言

         由於對Hibernate的二級快取和查詢快取的區別不瞭解,也不知道它們起什麼作用。於是動手做了一些實驗,對它們的組合使用有了一個表面的認識。

1.前提

         1) 不使用一級快取(Session級別)的情況。因為大部分api對session的操作都進行n層封裝,用完session就close,一般很少使用到一級快取。

         2) 開啟hibernate.show_sql=true,根據sql的是否輸出來判斷是否訪問了資料庫。

2.基礎

2.1.二級快取

         二級快取是SessionFactory級別的全域性快取,它為每個類(或集合)提供快取。凡是呼叫二級快取的查詢方法都會從中受益,比如load,list,iterate等方法(注意,get和find不使用快取,直接訪問資料庫)。

         開啟條件:

         1)hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider(這裡指定了ehcache)

         2)hbm.xml配置<cache usage="read-write"/>

         3)ehcache.xml定義該類的cache

         簡單地說,二級快取是用來儲存類物件的,並且填充它的所有屬性值。

2.2.查詢快取

         查詢快取儲存的是查詢方法(list和iterate等)查詢的sql語句和結果集,跟load這種裝載物件的方法沒有關係。也就是說,使用load方法,查詢快取不理睬。

         並且這個結果集只是物件id列表,物件的其他屬性值不儲存。例如,list執行的時候,先根據查詢快取中的sql語句,獲取物件id列表,然後再load(id)來取物件。

         開啟條件:

         1) hibernate.cache.use_query_cache=true

         2)Query或者Criteria使用時,設定setCacheable(true)

         簡單地說,查詢快取是用來儲存sql執行後獲取的物件id列表。下一次執行同一條sql時,可直接從查詢快取中獲取到物件id列表。

3.實驗

         以下對最常用的load和list方法進行二級快取和查詢快取的組合測試。load和list執行的結果,都是返回同一個物件。

3.1.四種組合

         二級快取和查詢快取的組合,根據開啟和不開啟兩種情況,劃分為四種組合(√代表開啟,×代表不開啟):

組合

二級快取

查詢快取

1

×

2

×

3

4

×

×

3.2.load實驗

         對同一個id,使用load執行兩次,觀察sql的輸出現象,也就是判斷第二次load是否訪問了資料庫。其中√代表輸出,×代表未輸出:

組合

第一次sql

第二次sql

結論

1

×

與查詢快取無關

2

3

×

4

         當開啟了二級快取,load先從快取中獲取物件,於是組合1和3的第二次sql都未輸出,即第二次查詢沒有訪問資料庫。

         當沒有開啟二級快取,load總是直接訪問資料庫的。也證明了,查詢快取與load方法無關。

3.3.list實驗

         對同一條sql語句,使用list執行兩次,觀察sql的輸出現象。其中√代表輸出,×代表未輸出:

組合

第一次sql

第二次sql

結論

1

list每次訪問資料庫都會填充二級快取,相當於二級快取無效

2

√(不一樣)

這兩條sql語句不一樣,第一條是list的,第二條是load的

3

×

4

         對組合1現象的解釋:

         當沒有開啟查詢快取時,list每次都會直接訪問資料庫,然後把二級快取給重新填充。也就是說,list在不開啟查詢快取的情況下,根本就沒有利用到二級快取的好處。

對組合2現象的解釋:

         第一條sql是list正常訪問資料庫的,但第二次執行list時,由於有了查詢快取,直接根據第一條sql獲取物件的id,此時由於沒有開啟二級快取,load(id)後也沒法從二級快取中拿資料,只好再次訪問資料庫。但在組合3中,load(id)可以從二級快取中拿資料,所以不用訪問資料庫。

3.4.小結

         在load和list方法中,使用二級快取和查詢快取的不同組合,效果出現了差別。特別強調的是,由於很多操作是基於list的,如果沒有開啟查詢快取,根本就使用不了二級快取的資料,也就提高不了效能了(但是iterate可以使用到二級快取)。

         另外,從表格中可以看出來,同時開啟二級快取和查詢快取,效果是最好的,第二次查詢都不需要訪問資料庫。

4.維護

         當存在除hibernate之外的改變資料庫資料的方式時,維護二級快取和查詢快取是很麻煩的。比如使用jdbc或者第三方系統修改了資料庫,hibernate都不知道,也就沒法自行維護快取了。這時需要手動維護,如果存在第三方系統,還需要讓第三方系統發訊息通知hibernate。

         維護手段也就是evict(清除某個類的二級快取)和evictQuery(清除查詢快取)。針對資料修改的三種形式,分別維護:

         1)insert:evictQuery

         2)delete:evict和evictQuery

         3)update:evict

一般來講ORM中的快取分為以下幾類:
         1:事務級快取:即在當前事務範圍內的資料快取. 就Hibernate來講,事務級快取是基於Session的生命週期實現的,每個Session內部會存在一個數據快取,它隨著 Session的建立而存在,隨著Session的銷燬而滅亡,因此也稱為Session Level Cache.
         2:應用級快取: 即在某個應用中或應用中某個獨立資料庫訪問子集中的共享快取,此快取可由多個事務共享(資料庫事務或應用事務),事務之間的快取共享策略與應用的事務隔離 機制密切相關.在Hibernate中,應用級快取由SessionFactory實現,所有由一個SessionFactory建立的 Session例項共享此快取,因此也稱為SessionFactory Level Cache.
         3:分散式快取:即在多個應用例項,多個JVM間共享的快取策略.分散式快取由多個應用級快取例項組成,通過某種遠端機制(RMI,JMS)實現各個快取例項間的資料同步,任何一個例項的資料修改,將導致整個叢集間的資料狀態同步.

  Hibernate的二級快取策略,是針對於ID查詢的快取策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache

查詢快取,快取的key是hql語句,快取的value是滿足hql語句的記錄的主鍵值。也就是說,查詢快取,只是快取資料庫記錄的主鍵值,並不會快取記錄的所有欄位值。

    預設hibernate不會開啟查詢快取,這是因為查詢快取只有在hql/hql語句語義完全一致的時候,才能命中。而實際查詢場景下,查詢條件、分頁、 排序等構成的複雜查詢sql語句很難完全一致。可能是hibernate覺得命中率低,所以預設關閉了查詢快取。我們可以根據實際使用情況,決定是否開啟 查詢快取,唯一的原則就是命中率要儘可能的高。如果針對A表的查詢,查詢sql語句基本都是完全一致的情況,就可以針對A使用查詢快取;如果B表的查詢條 件經常變化,很難命中,那麼就不要對B表使用查詢快取。這可能就是hibernate使用查詢快取的時候,既要在hibernate.cfg.xml中進 行配置,也需要query.setCacheable(true)的原因。

     查詢快取只對list有用,對iterate方式無用。iterate不會讀也不會寫查詢快取,list會讀也會寫查詢快取。查詢快取中的key是 sql語句(這些sql語句會被hibernate解析,保證語義相同的sql,能夠命中查詢快取),快取的value是記錄的主鍵值

Q:什麼樣的資料適合存放到第二級快取中?

    1.很少被修改的資料

    2.不是很重要的資料,允許出現偶爾併發的資料

    3.不會被併發訪問的資料

    4.參考資料,指的是供應用參考的常量資料,它的例項數目有限,它的例項會被許多其他類的例項引用,例項極少或者從來不會被修改。

 不適合存放到第二級快取的資料?

    1 經常被修改的資料

    2 財務資料,絕對不允許出現併發

    3 與其他應用共享的資料。

 hibernate快取的資料實時性思考?當資料變化時hibernate快取是否能自動更新?

下面是測試例子,經過測試hibernate查詢快取能“監聽”到當前快取實體的資料變化,即當對這個實體進行增加,刪除,修改時,查詢快取將重新去資料庫獲得最新的資料然後再快取起來。

前置配置:

http://www.360doc.com/content/14/0801/16/1073512_398635409.shtml

注意在實體對映檔案中配置:<!--二級快取一般設定為只讀--><cache usage="read-only" />

實驗:返回的是list

測試程式碼:

 DAO層的一個方法:

 public void testSession(){
        Session session=this.getSession();
    //List<TUser>    ls=session.createQuery("from TUser where username like '%h%'").setFirstResult(0).setMaxResults(2).list();
      List<TUser>    ls=session.createQuery("from TUser where username like ? ").setCacheable(true).setParameter(0, "%h%").setFirstResult(0).setMaxResults(30).list();
        for (TUser tUser : ls) {
            System.out.println(tUser.getUsername()+"=="+tUser.getId());
        }
    }

junit單元測試的一個方法:

    @Test
    public void testCache() {
        
        System.out.println("=====第一次讀取=======");
        userManager.testCache();
        System.out.println("====第二次讀取========");
        userManager.testCache();
        System.out.println("====新增一個使用者=======");
        TUser user=new TUser();
        user.setUsername("htt");
        user.setPassword("123");
        userManager.saveUser(user);
        System.out.println("====新增使用者後第一次讀取======");
        userManager.testCache();
        System.out.println("====新增使用者後第二次讀取======");
        userManager.testCache();
        System.out.println("====修改使用者=====");
        TUser user2=new TUser();
        user2.setId("1061");
        user2.setUsername("h22");
        user2.setPassword("123");
        userManager.update(user2);
        System.out.println("====修改使用者後第一次讀取======");
        userManager.testCache();
        System.out.println("====修改使用者後第二次讀取======");
        userManager.testCache();
        System.out.println("====刪除使用者=====");
        TUser user3=new TUser();
        user3.setId("1061");
        userManager.deleteUser(user3);
        System.out.println("====刪除使用者後第一次讀取======");
        userManager.testCache();
        System.out.println("====刪除使用者後第二次讀取======");
        userManager.testCache();
    }

場景一:開啟“查詢快取”,關閉二級快取。結果如下

=====第一次讀取=======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
====第二次讀取========
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
====新增一個使用者=======
Hibernate: select SEQ_USER.nextval from dual
Hibernate: insert into hzc.T_USER (USERNAME, PASSWORD, EMAIL, MOBILE, ID) values (?, ?, ?, ?, ?)
====新增使用者後第一次讀取======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
htt==1088
====新增使用者後第二次讀取======
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
htt==1088
====修改使用者=====
Hibernate: update hzc.T_USER set USERNAME=?, PASSWORD=?, EMAIL=?, MOBILE=? where ID=?
====修改使用者後第一次讀取======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
htt==1088
====修改使用者後第二次讀取======
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
h22==1061
htt==1082
htt==1083
htt==1085
htt==1088
====刪除使用者=====
Hibernate: delete from hzc.T_USER where ID=?
====刪除使用者後第一次讀取======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088
====刪除使用者後第二次讀取======
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
Hibernate: select tuser0_.ID as ID1_0_, tuser0_.USERNAME as USERNAME1_0_, tuser0_.PASSWORD as PASSWORD1_0_, tuser0_.EMAIL as EMAIL1_0_, tuser0_.MOBILE as MOBILE1_0_ from hzc.T_USER tuser0_ where tuser0_.ID=?
htt==1081
htt==1087
htt==1086
htt==1084
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088

場景一:開啟“查詢快取”,開啟二級快取。結果如下

log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====第一次讀取=======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
htt==1089
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088
====第二次讀取========
htt==1081
htt==1087
htt==1086
htt==1084
htt==1089
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088
====新增一個使用者=======
Hibernate: select SEQ_USER.nextval from dual
Hibernate: insert into hzc.T_USER (USERNAME, PASSWORD, EMAIL, MOBILE, ID) values (?, ?, ?, ?, ?)
====新增使用者後第一次讀取======
Hibernate: select * from ( select tuser0_.ID as ID1_, tuser0_.USERNAME as USERNAME1_, tuser0_.PASSWORD as PASSWORD1_, tuser0_.EMAIL as EMAIL1_, tuser0_.MOBILE as MOBILE1_ from hzc.T_USER tuser0_ where tuser0_.USERNAME like ? ) where rownum <= ?
htt==1081
htt==1087
htt==1086
htt==1084
htt==1089
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088
htt==1090
====新增使用者後第二次讀取======
htt==1081
htt==1087
htt==1086
htt==1084
htt==1089
hcc==1010
hzc==1004
htt==1082
htt==1083
htt==1085
htt==1088
htt==1090
====修改使用者=====