1.一級緩存(session裏面的實體對象,存放在內存中)
☞get/load/list/iterate可以將對象放入到一級緩存中
List操作不會利用一級緩存
☞get/load/iterate可以利用一級緩存
☞flush方法將改變後的同對象持久化到數據庫中
2.二級緩存
即SessionFactory級別的緩存。默認的情況下是打開的。這是一個全局緩存策略。它可以對對象的數據進行全局緩存。
一級緩存 二級緩存 緩存的是實體對象
緩存的key是ID,緩存的value是實體對象
3.查詢緩存(慎用)
即對查詢的結果集進行緩存處理,以便下次相同條件相同HQL的情況下可以直接從緩存中獲取數據。
查詢緩存的作用,是對list操作的查詢結果集進行緩存!
緩存的是普通結果集
緩存的key是HQL中的語句與參數,緩存的value則:
(1)如果查詢的結果爲普通結果集,則緩存這些結果集
(2)如果查詢的結果爲實體對象,則緩存實體對象的ID列表
用查詢緩存的時候,二級緩存也要啓用,防止發出多條語句
我們使用list操作的時候,如果啓用了查詢緩存,hibernate將根據當前查詢的HQL語句(及其參數值)計算出一個緩存的key值;查詢結果集,將作爲緩存的value值(但如果查詢結果集是一個對象結果集的話,其緩存的value值是對象的ID集合,而不是對象集合本身)。
<o:p> </o:p>
可以在hibernate配置文件中添加:
<property name="hibernate.cache.use_query_cache">true</property><o:p></o:p>
以便打開查詢緩存。
<o:p> </o:p>
查詢緩存,對對象查詢,將緩存其ID列表;對普通查詢,將緩存整個數據集合。所以,對於對象查詢,需要配合二級緩存來使用。
<o:p> </o:p>
在打開了查詢緩存之後,需要注意,調用query.list()操作之前,必須顯式調用query.setCachable(true)來標識某個查詢使用緩存。
4.批量抓取
(1)抓取策略,有一個對象 ,即如何獲取關聯的策略。
(2)什麼叫批量抓取:有一批對象,想得到這批對對象的關聯
(3)在many-to-one/one-to-many中設置:fetch(在hbm.xml語句中配置)
Fetch="select" 查詢抓取,通過第二條語句查詢關聯(這是默認值)
Fetch="join" 連接抓取,在加載的同時通過一條外連接已經把關聯的對象加載
上來了,所以設置的lazy配置失效
Fetch="join" 對於批量抓取的時候是無效的
當Fetch="select"可以定義批量抓取策略,在對方的class映射文件中配置batch-size
即可
連接抓取(Join fetching) - Hibernate通過 在SELECT語句使用OUTER JOIN(外連接)來 獲得對象的關聯實例或者關聯集合。 連接抓取策略可以被定義在<many-to-one/>或集合(如<set/>)標籤上。這種抓取策略,對load/get操作有效。
· 如在Student的<many-to-one/>標籤上設置fetch=”join”,當我們load/get一個Student的時候,其classes屬性的值,將通過一個outter join連接查詢來獲取
· 或在Classes類的<set />標籤上設置fetch=”join”,當我們load/get一個Classes類的實例的時候,其集合數據,也是通過一個outter join連接查詢來抓取
· 查詢抓取(Select fetching) - 另外發送一條 SELECT 語句抓取當前對象的關聯實體或集合。除非你顯式的指定lazy="false"禁止 延遲抓取(lazy fetching),否則只有當你真正訪問關聯關係的時候,纔會執行第二條select語句。 這種抓取策略,設置方法爲:fetch=”select”;
· 如在set標籤上設置fetch=”select”,下面的查詢:List list = session.createQuery("from Classes cls where id in (1,22)").list();將產生如下結果:
Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>
<o:p> </o:p>
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?<o:p></o:p>
<o:p> </o:p>
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?<o:p></o:p>
可見,總共發出:第一,查詢Classes的數據;第二,因爲查詢結果集中有兩個Classes對象,所以針對每個對象,都發出了一個查詢語句以便查詢其students集合的數據。<o:p></o:p>
· <o:p> </o:p>
· 子查詢抓取(Subselect fetching) - 另外發送一條SELECT 語句抓取在前面查詢到(或者抓取到)的所有實體對象的關聯集合。除非你顯式的指定lazy="false" 禁止延遲抓取(lazy fetching),否則只有當你真正訪問關聯關係的時候,纔會執行第二條select語句。 設置方法是:fetch=”subselect”,它只能被設置在集合映射的屬性上。
· 如在set標籤上設置fetch=”sebselect”,下面的查詢:List list = session.createQuery("from Classes cls where id in (1,22)").list();在list對象中,將包含兩個Classes對象的實例,假設其集合上配置lazy=”false”,我們立刻就能看到hibernate的subselect抓取策略是:
以下是hibernate生成的SQL語句:<o:p></o:p>
Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>
<o:p> </o:p>
☞悲觀鎖和樂觀鎖
兩個人同時修改用一條數據時,就會才產生數據不一致
這是我們需要用樂觀鎖來解決這個問題!
悲觀鎖:鎖定一條記錄,當修改成功後,對方纔能修改(一直等待)
在實體bean中設置
Person p=(Person)session.get(Person.class, 1,LockOptions.UPGRADE);
缺點:當遇到多個線程的時候,會發送死鎖,效率也不高(不建議使用)
樂觀鎖(建議使用):通過版本號約束hibernate是否更新,避免了數據更新的丟失,在實體類中加屬性版本號:int versionNumber ,在對應的映射文件中添加<version name="versionNumber"></version>
5.批量更新/保存
向數據庫中插入1萬條數據,如何提高效率?
對於在Mysql數據庫中加入<property name="hibernate.connection.url">(oracle數據庫中則不需要加入)
jdbc:mysql://localhost/hibernate?rewriteBatchedStatements=true</property>
//<property name="hibernate.jdbc.batch_size">25</property>