小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

[Java面試八]Hibernate總結(jié)以及在面試中的一些問題.

 黃建校 2016-10-11

1.為什么要使用Hibernate開發(fā)你的項目呢?Hibernate的開發(fā)流程是怎么樣的?

為什么要使用
.JDBC訪問數(shù)據(jù)庫的代碼做了封裝,大大簡化了數(shù)據(jù)訪問層繁瑣的重復(fù)性代碼。
.Hibernate 是一個基于JDBC的主流持久化框架,是一個優(yōu)秀的ORM 實現(xiàn)。他很大程度的簡化DAO層的編碼工作
.hibernate 的性能非常好,因為它是個輕量級框架。映射的靈活性很出色。它支持各種關(guān)系數(shù)據(jù)庫,從一對一到多對多的各種復(fù)雜關(guān)系。
開發(fā)流程
01987414-db11-4848-8ae2-3e956bdf36b8

2.什么是延遲加載?

    延遲加載機制是為了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數(shù)據(jù)的時候,才真正執(zhí)行數(shù)據(jù)加載操作。在Hibernate中提供了對實體對象的延遲加載以及對集合的延遲加載,另外在Hibernate3中還提供了對屬性的延遲加載。

3.說一下hibernate的緩存機制

Ahibernate一級緩存
1)hibernate支持兩個級別的緩存,默認只支持一級緩存;
2)每個Session內(nèi)部自帶一個一級緩存;
3)某個Session被關(guān)閉時,其對應(yīng)的一級緩存自動清除;
B:hibernate二級緩存
(1) 二級緩存獨立于session,默認不開啟;

4.Hibernate的查詢方式有哪些?

本地SQL查詢、Criteria、Hql

5.如何優(yōu)化Hibernate?

1.使用雙向一對多關(guān)聯(lián),不使用單向一對多
2.靈活使用單向一對多關(guān)聯(lián)
3.不用一對一,用多對一取代
4.配置對象緩存,不使用集合緩存
5.一對多集合使用Bag,多對多集合使用Set
6. 繼承類使用顯式多態(tài)
7. 表字段要少,表關(guān)聯(lián)不要怕多,有二級緩存撐腰 

6.Hibernate中GET和LOAD的區(qū)別?

    請注意如果沒有匹配的數(shù)據(jù)庫記錄,load()方法可能拋出無法恢復(fù)的異常(unrecoverable exception)。 如果類的映射使用了代理(proxy),load()方法會返回一個未初始化的代理,直到你調(diào)用該代理的某方法時才會去訪問數(shù)據(jù)庫。若你希望在某對象中創(chuàng)建一個指向另一個對象的關(guān)聯(lián),又不想在從數(shù)據(jù)庫中裝載該對象時同時裝載相關(guān)聯(lián)的那個對象,那么這種操作方式就用得上的了。 如果為相應(yīng)類映射關(guān)系設(shè)置了batch-size, 那么使用這種操作方式允許多個對象被一批裝載(因為返回的是代理,無需從數(shù)據(jù)庫中抓取所有對象的數(shù)據(jù))。 如果你不確定是否有匹配的行存在,應(yīng)該使用 get()方法,它會立刻訪問數(shù)據(jù)庫,如果沒有對應(yīng)的行,會返回null。
    session.get 方法, 查詢立即執(zhí)行 , 返回Customer類對象
    session.load 方法,默認采用延遲加載數(shù)據(jù)方式,不會立即查詢,返回 Customer類子類對象 (動態(tài)生成代理對象)
* 如果 PO類使用final修飾,load無法創(chuàng)建代理對象,返回目標對象本身 (load效果和 get效果 相同 ) 

7.說說在 hibernate中使用Integer做映射和使用int做映射之間有什么差別?

Integer codeint code的區(qū)別:
Integer是對象.      code=null;   對象可以為空.   
int 是普通類型,     不可能=null.       
根據(jù)你的數(shù)據(jù)庫code是可以空的,故應(yīng)該映射成Integer.      
你沒理由hbm.xml里寫 Integer,類里卻寫int

8.SQLHQL有什么區(qū)別?

sql 面向數(shù)據(jù)庫表查詢
hql 面向?qū)ο蟛樵?
 
hql:from 后面跟的 類名+類對象 where 后 用 對象的屬性做條件
sql:from 后面跟的是表名  where 后 用表中字段做條件
查詢
在Hibernate中使用查詢時,一般使用Hql查詢語句。
HQL(Hibernate Query Language),即Hibernate的查詢語言跟SQL非常相像。不過HQL與SQL的最根本的區(qū)別,就是它是面向?qū)ο蟮摹?
 
使用HQL時需要注意以下幾點:
1.大小寫敏感
因為HQL是面向?qū)ο蟮?,而對象類的名稱和屬性都是大小寫敏感的,所以HQL是大小寫敏感的。
HQL語句:from Cat as cat where cat.id > 1;與from Cat as cat where cat.ID > 1;是不一樣的,這點與SQL不同。
2.from子句
from Cat,該句返回Cat對象實例,開發(fā)人員也可以給其加上別名,eg. from Cat as cat,對于多表查詢的情況,可參考如下:
from Cat as cat, Dog as dog
其它方面都與SQL類似,在此不再贅述。

9.Hibernate的分頁查詢

例如:從數(shù)據(jù)庫中的第20000條數(shù)據(jù)開始查后面100條記錄
Query q = session.createQuery("from Cat as c");;   
q.setMaxResults(100);;   
List l = q.list();;
q.setFirstResult(20000);;  

10.Hibernate中Java對象的狀態(tài)以及對應(yīng)的特征有哪些?

持久化對象的三種狀態(tài)
    持久化對象POOID
PO=POJO + hbm
映射配置
    編寫規(guī)則
  1. 必須提供無參數(shù)public構(gòu)造器
  2. 所有屬性private,提供publicgettersetter方法
  3. 必須提供標識屬性,與數(shù)據(jù)表中主鍵對應(yīng),例如Customer id屬性
  4. PO類屬性應(yīng)盡量使用基本數(shù)據(jù)類型的包裝類型(區(qū)分空值)  例如int---Integer  long---Long
  5. 不要用final修飾(將無法生成代理對象進行優(yōu)化)
OID 指與數(shù)據(jù)表中主鍵對應(yīng) PO類中屬性,例如 Customer id屬性
    Hibernate框架使用OID來區(qū)分不同PO對象
        * 例如內(nèi)存中有兩個PO對象,只要具有相同 OID, Hibernate認為同一個對象
    * Hibernate 不允許緩存同樣OID
的兩個不同對象
     
①瞬時態(tài)(臨時態(tài)、自由態(tài)):不存在持久化標識OID,尚未與Hibernate Session關(guān)聯(lián)對象,被認為處于瞬時態(tài),失去引用將被JVM回收
②持久態(tài):存在持久化標識
OID,與當前session有關(guān)聯(lián),并且相關(guān)聯(lián)的session沒有關(guān)閉 ,并且事務(wù)未提交
③脫管態(tài)
(離線態(tài)、游離態(tài)):存在持久化標識OID,但沒有與當前session關(guān)聯(lián),脫管狀態(tài)改變hibernate
不能檢測到

    區(qū)分三種狀態(tài):判斷對象是否有OID,判斷對象是否與session關(guān)聯(lián)(被一級緩存引用)
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
Book book =newBook();// 瞬時態(tài)(沒有OID,未與Session關(guān)聯(lián))
book.setName("hibernate精通");
book.setPrice(56d);
 
session.save(book);// 持久態(tài)(具有OID,與Session關(guān)聯(lián))
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
 
System.out.println(book.getId());// 脫管態(tài)(具有 OID,與Session斷開關(guān)聯(lián))
持久化對象狀態(tài)轉(zhuǎn)換
    ceb8decb-fd8e-4b0e-a5bf-a7e7bcc79ec5
    瞬時態(tài)對象:通過new獲得
        瞬時----->持久    save、saveOrUpdate(都是session)
        瞬時----->脫管    book.setId(1) 為瞬時對象設(shè)置OID

    持久態(tài)對象:通過get/load 、Query查詢獲得
持久----->瞬時    delete  (被刪除持久化對象 不建議再次使用 )
持久----->脫管    evict(清除一級緩存中某一個對象)、close(關(guān)閉Session,清除一級緩存)、clear(清除一級緩存所有對象 )
    脫管態(tài)對象 無法直接獲得
脫管----->瞬時    book.setId(null); 刪除對象OID
脫管----->持久    update、saveOrUpdate、 lock(過時)

11.Hibernate中怎樣處理事務(wù)?

Hibernate是對JDBC的輕量級對象封裝,Hibernate本身是不具備Transaction 處理功能的,HibernateTransaction實際上是底層的JDBC Transaction的封裝,或者是JTA Transaction的封裝,下面我們詳細的分析:
Hibernate可以配置為JDBCTransaction或者是JTATransaction,這取決于你在hibernate.properties中的配置:

  1. #hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
  2. #hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
如果你什么都不配置,默認情況下使用JDBCTransaction,如果你配置為:

hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
將使用JTATransaction,不管你準備讓Hibernate使用JDBCTransaction,還是JTATransaction,我的忠告就是什么都不配,將讓它保持默認狀態(tài),如下:
 

  1. #hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
  2. #hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
在下面的分析中我會給出原因。

一、JDBC Transaction
看看使用JDBC Transaction的時候我們的代碼例子:

  1. Session session = sf.openSession();
  2. Transaction tx = session.beginTransactioin();
  3. ...
  4. session.flush();
  5. tx.commit();
  6. session.close();
這是默認的情況,當你在代碼中使用HibernateTransaction的時候?qū)嶋H上就是JDBCTransaction。那么JDBCTransaction究竟是什么東西呢?來看看源代碼就清楚了:

Hibernate2.0.3源代碼中的類

  1. net.sf.hibernate.transaction.JDBCTransaction:
  2. public void begin() throws HibernateException {
  3.     ...
  4.     if (toggleAutoCommit) session.connection().setAutoCommit(false);
  5.     ...
  6. }
這是啟動Transaction的方法,看到 connection().setAutoCommit(false) 了嗎?是不是很熟悉?

再來看

  1. public void commit() throws HibernateException {
  2.     ...
  3.     try {
  4.         if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
  5.     try {
  6.         session.connection().commit();
  7.         committed = true;
  8.     }
  9.     ...
  10.     toggleAutoCommit();
  11. }
這是提交方法,看到connection().commit() 了嗎?下面就不用我多說了,這個類代碼非常簡單易懂,通過閱讀使我們明白HibernateTransaction都在干了些什么?我現(xiàn)在把用 Hibernate寫的例子翻譯成JDBC,大家就一目了然了:
  1. Connection conn = ...; <--- session = sf.openSession();
  2. conn.setAutoCommit(false); <--- tx = session.beginTransactioin();
  3. ... <--- ...
  4. conn.commit(); <--- tx.commit(); (對應(yīng)左邊的兩句)
  5. conn.setAutoCommit(true);
  6. conn.close(); <--- session.close();
    看明白了吧,HibernateJDBCTransaction根本就是conn.commit而已,根本毫無神秘可言,只不過在Hibernate中, Session打開的時候,就會自動conn.setAutoCommit(false),不像一般的JDBC,默認都是true,所以你最后不寫 commit也沒有關(guān)系,由于Hibernate已經(jīng)把AutoCommit給關(guān)掉了,所以用Hibernate的時候,你在程序中不寫 Transaction的話,數(shù)據(jù)庫根本就沒有反應(yīng)。

12.簡單的介紹一下Hibernate的核心API?

1.Configuration
    用于加載hibernate配置
    加載核心屬性配置hibernate.properties和hibernate.cfg.xml
//方式一src 讀取 hibernate.properties 屬性配置文件
Configuration cfg =newConfiguration(); 
//方式二:去src讀取 hibernate.cfg.xml  
Configuration cfg =newConfiguration().configure(); 
 Configuration cfg =newConfiguration().configure("自定義xml文件");src 加載指定文件 
 
    手動加載hbm映射配置,持久化類與數(shù)據(jù)表的映射關(guān)系(*.hbm.xml 文件)
如果沒有對PO類進行hbm映射,會報錯 :
org.hibernate.MappingException:Unknown entity: cn.itcast.domain.Customer 
        那么我們可以手動加載其映射文件:
//方式一:
configuration.addResource("cn/itcast/domain/Customer.hbm.xml");加載hbm文件 
//方式二:
configuration.addClass(Customer.class);加載Class,自動搜索hbm映射文件
    * 如果使用 hibernate.cfg.xml配置,將映射配置xml中 <mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
 
2.SessionFactory
    保存了當前的數(shù)據(jù)庫配置信息和所有映射關(guān)系以及預(yù)定義的SQL語句這個對象是線程安全的
//預(yù)定義SQL語句
<sql-queryname="login">
    <![CDATA[select * from user where username= ? and password =?]]>
</sql-query>
3.Session
    代表hibernate操作會話對象,相當于Connection 
session是一個單線程對象,線程不安全(在方法內(nèi)部定義和使用Session,不會出現(xiàn)線程問題)
* 每個線程方法調(diào)用棧,是線程私有的
session 進行PO(Persistent Object)對象常見持久化操作, 存在一級緩存
    常用API
save 完成插入
update 完成修改
delete完成刪除
get/load 根據(jù)主鍵字段查詢
createQuery、 createSQLQuery 創(chuàng)建查詢對象Query接收HQL,SQLQuery接收SQL
createCriteria()  面向?qū)ο髼l件查詢
4.Transaction 事務(wù)操作
commit 提交
rollback 回滾
    如果沒有開啟事務(wù),那么每個Session的操作,都相當于一個獨立的事務(wù)
* 事務(wù)是否提交
//默認false
<property name="hibernate.connection.autocommit">false</property> 事務(wù)不提交
<propertyname="hibernate.connection.autocommit">true</property> 事務(wù)提交
5.Query
    session.createQuery()獲得
面向?qū)ο蟛樵?,操作類,操作屬?/span>
接收參數(shù) HQL語句
開發(fā)代碼步驟
    獲得HibernateSession對象
    編寫HQL語句
    調(diào)用session.createQuery 創(chuàng)建查詢對象
    如果HQL語句包含參數(shù),則調(diào)用QuerysetXXX設(shè)置參數(shù)
    調(diào)用Query對象的list()uniqueResult()方法執(zhí)行查詢
6.Criteria 接口(QBC查詢 Query By Criteria )
  主要為了解決多條件查詢問題,以面向?qū)ο蟮姆绞教砑訔l件,無需拼接HQL語句 

13.update與saveOrUpdate有什么區(qū)別?

save() 方法很顯然是執(zhí)行保存操作的,如果是對一個新的剛new出來的對象進行保存,自然要使用這個方法了,數(shù)據(jù)庫中沒有這個對象。
update()
如果是對一個已經(jīng)存在的托管對象進行更新那么肯定是要使用update()方法了,數(shù)據(jù)中有這個對象。
saveOrUpdate()
這個方法是更新或者插入,有主鍵就執(zhí)行更新,如果沒有主鍵就執(zhí)行插入?!?span style="background-color: #ffad5b;">此方法慎用
    HibernatesaveOrUpdate()方法在執(zhí)行的時候,先會去session中去找存不存在指定的字段,如果存在直接update,否則save,這個時候問題就發(fā)生了。
    有兩張表,表A和表B,這兩張表的主鍵都是一樣的,例如都是MASTER_ID,同時對應(yīng)的BO里面屬性都是masterID,現(xiàn)在要執(zhí)行的操作是,以 MASTER_ID為條件將表A中的數(shù)據(jù)查詢出來,然后將部分值插入到表B中,然后再更新表B,在查詢表A后,session中已經(jīng)存在masterID 了,這個時候再去對表B進行savaOrUpdate的時候,Hibernate會發(fā)現(xiàn)session中已經(jīng)存在masterID了,所以執(zhí)行的就是 update,但是實際上表B中根本不存在masterID這個值,當你執(zhí)行完查詢數(shù)據(jù)庫的時候會發(fā)現(xiàn)沒有插入數(shù)據(jù),像這種情況,就得先用 masterID對表B進行查詢,當返回的BONULL時,new一個新BO然后再進行插入,這個時候用到的就是createbo了。

14.Hibernate的inverse屬性的作用?

1.明確inversecascade的作用 
inverse 
決定是否把對對象中集合的改動反映到數(shù)據(jù)庫中,所以inverse只對集合起作用,也就是只對one-to-manymany-to-many有效(因為只有這兩種關(guān)聯(lián)關(guān)系包含集合,而one-to-onemany-to-one只含有關(guān)系對方的一個引用)。

cascade
決定是否把對對象的改動反映到數(shù)據(jù)庫中,所以cascade對所有的關(guān)聯(lián)關(guān)系都起作用(因為關(guān)聯(lián)關(guān)系就是指對象之間的關(guān)聯(lián)關(guān)系)。

2.inverse屬性 :inverse所描述的是對象之間關(guān)聯(lián)關(guān)系的維護方式。
inverse
只存在于集合標記的元素中 。Hibernate提供的集合元素包括<set/> <map/> <list/> <array /> <bag />
Inverse
屬性的作用是:是否將對集合對象的修改反映到數(shù)據(jù)庫中。 inverse屬性的默認值為false,表示對集合對象的修改會被反映到數(shù)據(jù)庫中;inverse=false 的為主動方,由主動方負責維護關(guān)聯(lián)關(guān)系。  inverse=”true” 表示對集合對象的修改不會被反映到數(shù)據(jù)庫中。
為了維持兩個實體類(表)的關(guān)系,而添加的一些屬性,該屬性可能在兩個實體類(表)或者在一個獨立的表里面,這個要看這雙方直接的對應(yīng)關(guān)系了: 這里的維護指的是當主控放進行增刪改查操作時,會同時對關(guān)聯(lián)關(guān)系進行對應(yīng)的更新。
   
一對多: 該屬性在多的一方。應(yīng)該在一方的設(shè)置 inverse=true ,多的一方設(shè)置 inverse=false(多的一方也可以不設(shè)置inverse屬性,因為默認值是false),這說明關(guān)聯(lián)關(guān)系由多的一方來維護。如果要一方維護關(guān) 系,就會使在插入或是刪除""方時去update""方的每一個與這個""的對象有關(guān)系的對象。而如果讓""方面維護關(guān)系時就不會有update 操作,因為關(guān)系就是在多方的對象中的,直指插入或是刪除多方對象就行了。顯然這樣做的話,會減少很多操作,提高了效率。
注:單向one-to-many關(guān)聯(lián)關(guān)系中,不可以設(shè)置inverse="true",因為被控方的映射文件中沒有主控方的信息。
   多對多: 屬性在獨立表中。inverse屬性的默認值為false。在多對多關(guān)聯(lián)關(guān)系中,關(guān)系的兩端 inverse不能都設(shè)為false,即默認的情況是不對的,如果都設(shè)為false,在做插入操作時會導(dǎo)致在關(guān)系表中插入兩次關(guān)系。也不能都設(shè)為 true,如果都設(shè)為true,任何操作都不會觸發(fā)對關(guān)系表的操作。因此在任意一方設(shè)置inverse=true,另一方inverse=false。
   
一對一: 其實是一對多的一個特例,inverse 的設(shè)置也是一樣的,主要還是看關(guān)聯(lián)關(guān)系的屬性在哪一方,這一方的inverse=false。
   
多對一: 也就是一對多的反過來,沒什么區(qū)別。

3.cascade屬性
級聯(lián)操作:指當主控方執(zhí)行某項操作時,是否要對被關(guān)聯(lián)方也執(zhí)行相同的操作。
cascade屬性的作用是描述關(guān)聯(lián)對象進行操作時的級聯(lián)特性。因此,只有涉及到關(guān)系的元素才有cascade屬性。具有cascade屬性的標記包括<many-to-one /> <one-to-one /> <any /> <set /><bag /> <idbag /> <list /> <array />
注意:<one-to-many /> <many-to-many />是用在集合標記內(nèi)部的,所以是不需要cascade屬性的。

4.inversecascade的區(qū)別
作用的范圍不同:
    Inverse是設(shè)置在集合元素中的。
    Cascade對于所有涉及到關(guān)聯(lián)的元素都有效。
    <many-to-one/><ont-to-many/>沒有inverse屬性,但有cascade屬性
執(zhí)行的策略不同
    Inverse 會首先判斷集合的變化情況,然后針對變化執(zhí)行相應(yīng)的處理。
    Cascade 是直接對集合中每個元素執(zhí)行相應(yīng)的處理
執(zhí)行的時機不同
    Inverse是在執(zhí)行SQL語句之前判斷是否要執(zhí)行該SQL語句
    Cascade則在主控方發(fā)生操作時用來判斷是否要進行級聯(lián)操作
執(zhí)行的目標不同
    Inverse對于<ont-to-many><many-to-many>處理方式不相同。
    對于<ont-to-many>,inverse所處理的是對被關(guān)聯(lián)表進行修改操作。
    對于<many-to-many>,inverse所處理的則是中間關(guān)聯(lián)表
    Cascade不會區(qū)分這兩種關(guān)系的差別,所做的操作都是針對被關(guān)聯(lián)的對象。
總結(jié) 
<one-to-many>

    <one-to-many>中,建議inverse=”true”,由“many”方來進行關(guān)聯(lián)關(guān)系的維護
    <many-to-many>中,只設(shè)置其中一方inverse=”false”,或雙方都不設(shè)置
    Cascade,通常情況下都不會使用。特別是刪除,一定要慎重。
操作建議:
    一般對many-to-onemany-to-many不設(shè)置級聯(lián),這要看業(yè)務(wù)邏輯的需要;one-to-oneone-to-many設(shè)置級聯(lián)。
    many-to-many關(guān)聯(lián)關(guān)系中,一端設(shè)置inverse=”false”,另一端設(shè)置為inverse=”true”。在one-to-many關(guān)聯(lián)關(guān)系中,設(shè)置inverse=”true”,由多端來維護關(guān)系表


Hibernate一級緩存相關(guān)問題

1.Session中的一級緩存
    Hibernate框架共有兩級緩存, 一級緩存(Session級別緩存)、二級緩存(SessionFactory級別緩存)
    在Session接口的實現(xiàn)中包含一系列的 Java 集合, 這些 Java 集合構(gòu)成了 Session 緩存.  持久化對象保存Session一級緩存中(一級緩存引用持久化對象地址),只要 Session 實例沒有結(jié)束生命周期, 存放在它緩存中的對象也不會結(jié)束生命周期
    Hibernate Session接口的實現(xiàn)類SessionImpl類(查看源碼,右擊session,選擇Open Type Hierarchy) ,里面有2個重要的字段:
*private transient ActionQueue actionQueue;                       ----行動隊列(標記數(shù)據(jù)活動)
*private transient StatefulPersistenceContext persistenceContext;----持久化上下文 
    當session的save()方法持久化一個對象時,該對象被載入緩存,以后即使程序中不再引用該對象,只要緩存不清空,該對象仍然處于生命周期中。當試圖get()、 load()對象時,會判斷緩存中是否存在該對象,有則返回,此時不查詢數(shù)據(jù)庫。沒有再查詢數(shù)據(jù)庫
    Session 能夠在某些時間點, 按照緩存中對象的變化來執(zhí)行相關(guān)的 SQL 語句, 來同步更新數(shù)據(jù)庫, 這一過程被稱為刷出緩存(flush)
        *  Transaction的commit()
        *  應(yīng)用程序執(zhí)行一些查詢操作時
        *  調(diào)用Session的flush()方法

    驗證一級緩存的存在
Book book =(Book) session.get(Book.class,1);// 第一次查詢,緩存中沒有
System.out.println(book);
 
Book book2 =(Book) session.get(Book.class,1);// 因為第一次查詢,對象已經(jīng)被放入1級緩存,不會查詢數(shù)據(jù)
System.out.println(book2);
 
*生成一條SQL語句,返回同一個對象,第一次查詢生成SQL,查詢對象,將對象放入一級緩存,第二次查詢,直接從一級緩存獲得
    06313632-5fa2-41bd-8eb0-cb3dbcf074df
    測試Hibernate快照 (深入理解一級緩存內(nèi)存結(jié)構(gòu)原理)
    hibernate 向一級緩存放入數(shù)據(jù)時,同時保存快照數(shù)據(jù)(數(shù)據(jù)庫備份),當修改一級緩存數(shù)據(jù),在flush操作時,對比緩存和快照,如果不一致,自動更新(將緩存的內(nèi)容同步到數(shù)據(jù)庫,更新快照)
*  快照區(qū)使用,在Session 保存一份與數(shù)據(jù)庫相同的數(shù)據(jù),在session的flush時, 通過快照區(qū)比較得知一級緩存數(shù)據(jù)是否改變,如果改變執(zhí)行對應(yīng)操作(update)
/**
* 測試快照區(qū)的使用
  */
@Test
publicvoid demo3(){
    // 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
 
book.setName("深入淺出Hibernate技術(shù)");// 修改書名(一級緩存被修改,自動update)
 
// 沒有手動執(zhí)行update,因為快照區(qū)原因,自動更新
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
}
    使用Debug模式進行截圖說明:
    我們重點關(guān)注session中的2個屬性actionQueue和persistenceContext
7f2c4be2-ee6d-40fa-94c5-8c700599438b
    大白話解析
        **當執(zhí)行g(shù)et后,緩存里面有數(shù)據(jù)了,活動隊列沒有發(fā)生變化,說明沒有需要提交到數(shù)據(jù)的內(nèi)容,PersistenceContext里面有內(nèi)容了。
            我們說,持久化上下文里面存放的是一個Map,它的鍵為一級緩存對象,值為快照(它是一級緩存對象的一個副本)。
        **當執(zhí)行setName后,一級緩存里面的數(shù)據(jù)發(fā)生了改變,在緩存flush時,會對比緩存和快照,如果不一致,那么會將緩存中的內(nèi)容同步到數(shù)據(jù)庫,并更新快照!
*  Hibernate中 持久態(tài) 對象具有自動更新數(shù)據(jù)庫能力 (持久態(tài)對象 才保存在 Session中,才有快照 )
2.一級緩存常見操作
    所有操作需要使用斷點調(diào)試才能看得比較清楚!
    1)flush : 修改一級緩存數(shù)據(jù)針對內(nèi)存操作,需要在session執(zhí)行flush操作時,將緩存變化同步到數(shù)據(jù)庫
     * 只有在緩存數(shù)據(jù)與快照區(qū)不同時,生成update語句
    2)clear : 清除所有對象 一級緩存
    3)evict : 清除一級緩存指定對象
    4)refresh :重新查詢數(shù)據(jù)庫,更新快照和一級緩存
@Test
// Session 對于 一級緩存操作
publicvoid demo4(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
 
// book.setPrice(80d); // 修改一級緩存數(shù)據(jù)
// 將緩存內(nèi)容同步到數(shù)據(jù)庫
// session.flush();
 
// 清除一級緩存所有數(shù)據(jù)
// session.clear();
 
// 清除一級緩存中 指定對象
// session.evict(book);
 
book.setPrice(30d);// 一級緩存改變
session.refresh(book);// 用數(shù)據(jù)庫內(nèi)容 覆蓋快照區(qū)和一級緩存
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
}
3.一級緩存刷出時間點設(shè)置 (FlushMode)
ALWAYS :在每次查詢時,session都會flush  (不要求 )
AUTO   : 在有些查詢時,session會flush  (默認)  ---------- 查詢、commit 、session.flush
COMMIT : 在事務(wù)提交時,session會flush   ------- commit 、session.flush
MANUAL :只有手動調(diào)用  session.flush 才會刷出  ----  session.flush
刷出條件(時間點嚴格程度 )
MANUAL > COMMIT> AUTO> ALWAYS
@Test
// 理解 FlushMode作用
publicvoid demo5(){
// 獲得Session
Session session =HibernateUtils.openSession();
 
// 設(shè)置 flushMode
session.setFlushMode(FlushMode.MANUAL);
 
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
// 查詢id 為1 的圖書對象
Book book =(Book) session.get(Book.class,1);// 第一次查詢,將對象加入一級緩存
System.out.println(book);
 
book.setPrice(1000d);// 修改價格
 
session.createQuery("from Book").list();// 查詢所有圖書 (AUTO 級別 flush)
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();// (COMMIT 級別 flush)
 
// session.flush(); // MANUAL 級別 flush
 
session.close();
}
4.session持久化對象操作方法
    1) save 將數(shù)據(jù)保存到數(shù)據(jù)庫 , 將瞬時對象轉(zhuǎn)換持久對象 
持久化對象,不允許隨便修改 OID
    2) update 更新數(shù)據(jù) ,主要用于脫管對象的更新(持久對象,可以根據(jù)快照自動更新 ), 將脫管對象轉(zhuǎn)換持久對象        
@Test
// 脫管對象更新
publicvoid demo6(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
Book book =newBook();// 瞬時
book.setId(1);// 脫管
book.setName("java入門");
book.setPrice(40d);
 
session.update(book);// 持久
 
session.flush();
 
// book.setPrice(50d);
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
}
        問題一: 調(diào)用update,默認直接生成update語句,如果數(shù)據(jù)沒有改變,不希望生成update
    在hbm文件 <class>元素 添加 select-before-update="true"
<classname="cn.itcast.domain.firstcache.Book"table="book"catalog="hibernate3day2"select-before-update="true">
問題二: 當update,脫管對象變?yōu)槌志脤ο螅?一級緩存不允許出現(xiàn)相同OID 兩個持久對象
@Test
// 一級緩存 存在兩個相同OID 持久態(tài)對象 報錯
publicvoid demo7(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
// 查詢
// Book b = (Book) session.get(Book.class, 1); // 持久
 
Book book =newBook();// 瞬時
book.setId(1);// 脫管
book.setName("java入門");
book.setPrice(50d);
session.update(book);// 持久
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
}
    org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [cn.itcast.domain.firstcache.Book#1]
問題三: 脫管對象 OID 在數(shù)據(jù)表中不存在,update時,發(fā)生異常
    org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.itcast.domain.firstcache.Book#20]

    3) saveOrUpdate , 如果參數(shù)是一個瞬時對象執(zhí)行save, 如果參數(shù)是一個脫管對象執(zhí)行update, 如果參數(shù)是持久對象直接返回
判斷對象是瞬時對象 : OID為null , 在hbm文件中為 <id>元素指定 unsaved-value屬性,如果PO對象OID為 unsaved-value 也是瞬時對象
<id name="id" unsaved-value="-1">  如果對象 OID為-1 也是瞬時對象,此時執(zhí)行的是save操作
@Test
// PO對象,OID為 hbm文件 配置 unsaved-value 也是瞬時對象, saveOrUpdate 執(zhí)行 save操作
publicvoid demo8(){
// 獲得Session
Session session =HibernateUtils.openSession();
// 開啟事務(wù)
Transaction transaction = session.beginTransaction();
 
Book book =newBook();// 瞬時
book.setId(-1);// 存在OID , -1是unsaved-value 也是瞬時
book.setName("xxx");
book.setPrice(100d);
 
session.saveOrUpdate(book);
 
// 提交事務(wù),關(guān)閉Session
transaction.commit();
session.close();
}
    4) get/load
        如果查詢OID不存在, get方法返回 null , load 方法返回代理對象 (代理對象初始化時拋出 ObjectNotFoundException )
    5) delete 方法既可以刪除一個脫管對象, 也可以刪除一個持久化對象
        **如果刪除脫管,先將脫管對象 與 Session 關(guān)聯(lián),然后再刪除
**執(zhí)行delete,先刪除一級緩存數(shù)據(jù),在session.flush 操作時,刪除數(shù)據(jù)表中數(shù)據(jù)


Hibernate二級緩存相關(guān)問題

1.二級緩存的相關(guān)介紹

緩存好處: 將數(shù)據(jù)庫或者硬盤數(shù)據(jù),保存在內(nèi)存中,減少數(shù)據(jù)庫查詢次數(shù),減少硬盤交互,提高檢索效率

    hibernate 共有兩個級別的緩存

        * 一級緩存,保存Session中, 事務(wù)范圍的緩存

        * 二級緩存,保存SessionFactory ,進程范圍的緩存

    SessionFacoty 兩部分緩存

    內(nèi)置 Hibernate 自帶的, 不可卸載. 通常在 Hibernate 的初始化階段, Hibernate 會把映射元數(shù)據(jù)和預(yù)定義的 SQL 語句放到 SessionFactory 的緩存中, 映射元數(shù)據(jù)是映射文件中數(shù)據(jù)的復(fù)制, 而預(yù)定義 SQL 語句時 Hibernate 根據(jù)映射元數(shù)據(jù)推到出來的. 該內(nèi)置緩存是只讀的.

 

    外置 :一個可配置的緩存插件. 在默認情況下, SessionFactory 不會啟用這個緩存插件. 外置緩存中的數(shù)據(jù)是數(shù)據(jù)庫數(shù)據(jù)的復(fù)制, 外置緩存的物理介質(zhì)可以是內(nèi)存或硬盤,必須引入第三方緩存插件才能使用。


2.二級緩存的內(nèi)部結(jié)構(gòu)以及存儲特點
Hibernate二級緩存分為:   
    * 類緩存區(qū)域
    * 集合緩存區(qū)域
    * 更新時間戳區(qū)域
    *
查詢緩存區(qū)域

68725fa5-da27-4eff-9b0b-080d2051517e
類緩存區(qū)數(shù)據(jù)存儲特點
* 從二級緩存區(qū)返回數(shù)據(jù)每次地址都是不同的(散裝數(shù)據(jù) 。每次查詢二級緩存,都是將散裝數(shù)據(jù)構(gòu)造為一個新的對象
4429f183-caf3-4141-ba88-a984f97bac02
集合緩存區(qū)
415e97a5-0600-4ccd-a964-f37892470bd7
如果注釋掉 Order類緩存,orders 集合無法緩存
* 集合緩存區(qū)數(shù)據(jù)緩存依賴類緩存區(qū)數(shù)據(jù)緩存

 

** 一級緩存的操作會同步到二級緩存

更新時間戳區(qū)域

作用:記錄數(shù)據(jù)最后更新時間,確保緩存數(shù)據(jù)是有效的

    Hibernate 提供了和查詢相關(guān)的緩存區(qū)域:

    **時間戳緩存區(qū)域: org.hibernate.cahce.UpdateTimestampCache
    時間戳緩存區(qū)域存放了對于查詢結(jié)果相關(guān)的表進行插入, 更新或刪除操作的時間戳.  Hibernate 通過時間戳緩存區(qū)域來判斷被緩存的查詢結(jié)果是否過期, 其運行過程如下:
    T1
時刻執(zhí)行查詢操作, 把查詢結(jié)果存放在 QueryCache 區(qū)域, 記錄該區(qū)域的時間戳為 T1
    T2
時刻對查詢結(jié)果相關(guān)的表進行更新操作, Hibernate T2 時刻存放在 UpdateTimestampCache 區(qū)域.
    T3
時刻執(zhí)行查詢結(jié)果前, 先比較 QueryCache 區(qū)域的時間戳和 UpdateTimestampCache 區(qū)域的時間戳, T2 >T1, 那么就丟棄原先存放在 QueryCache 區(qū)域的查詢結(jié)果, 重新到數(shù)據(jù)庫中查詢數(shù)據(jù), 再把結(jié)果存放到 QueryCache 區(qū)域; T2 < T1, 直接從 QueryCache
中獲得查詢結(jié)果。
8dd017ca-54a8-4691-9834-e9aea4ff8db0
**更新時間戳區(qū)域,記錄數(shù)據(jù)最后更新時間,在使用二級緩存時,比較緩存時間t1 更新時間 t2 , 如果 t2 > t1 丟棄原來緩存數(shù)據(jù),重新查詢緩存
查詢緩存
    有人稱查詢緩存 為hibernate 第三級緩存

* 二級緩存緩存數(shù)據(jù)都是類對象數(shù)據(jù),數(shù)據(jù)都是緩存在 "類緩存區(qū)域" ,二級緩存緩存PO類對象,條件(key)id

    查詢緩存適用場合:

        **應(yīng)用程序運行時經(jīng)常使用查詢語句

        **很少對與查詢語句檢索到的數(shù)據(jù)進行插入, 刪除和更新操作

    如果查詢條件不是id查詢, 緩存數(shù)據(jù)不是PO類完整對象 =====> 不適合使用二級緩存

查詢緩存: 緩存的是查詢數(shù)據(jù)結(jié)果, key是查詢生成SQL語句  , 查詢緩存比二級緩存功能更加強大

適用查詢緩存的步驟
    1)配置二級緩存(查詢緩存依賴二級緩存)

    2)啟用查詢緩存 hibernate.cfg.xml

 

<property name="hibernate.cache.use_query_cache">true</property>
    3)必須在程序中指定使用查詢緩存

 

query.setCacheable(true);
3.二級緩存的并發(fā)策略

    transactional  提供Repeatable Read事務(wù)隔離級別,緩存支持事務(wù),發(fā)生異常的時候,緩存也能夠回滾

    read-write     提供Read Committed事務(wù)隔離級別,更新緩存的時候會鎖定緩存中的數(shù)據(jù)

    nonstrict-read-write :導(dǎo)致臟讀, 很少使用

    read-only      數(shù)據(jù)不允許修改,只能查詢

* 很少被修改,不是很重要,允許偶爾的并發(fā)問題, 適合放入二級緩存??紤]因素(二級緩存監(jiān)控【后面學(xué)習(xí)】,它是是否采用二級緩存主要參考指標)

4.Hibernate支持哪些二級緩存技術(shù)?
    EHCache  (主要學(xué)習(xí),支持本地緩存,支持分布式緩存)
        可作為進程范圍內(nèi)的緩存, 存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤, 對 Hibernate 的查詢緩存提供了支持。
    *  OSCache
        可作為進程范圍內(nèi)的緩存, 存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤, 提供了豐富的緩存數(shù)據(jù)過期策略, 對 Hibernate 的查詢緩存提供了支持
    *  SwarmCache
        可作為集群范圍內(nèi)的緩存, 但不支持 Hibernate 的查詢緩存
    *  JBossCache
        可作為集群范圍內(nèi)的緩存, 支持 Hibernate 的查詢緩存

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多