標籤:style blog class code java c
上篇文章討論了Hibernate持久對象的生命週期,在整個生命週期中一個對象會經曆三個狀態,三種狀態的轉換過程在開發過程中是可控的,而且是通過使用方法來控制它們的轉化過程,具體的轉化過程今天就來著重討論下。
二、狀態轉化方法
前面說到對象之間的轉化過程是通過使用方法來實現的,這些方法是很重要的,先看張圖
上面這張圖在三篇文章中都有用到,它詳細描述了持久對象三種狀態的轉換過程及具體的轉化方法,另外還有記憶體回收行程,對象在瞬態和脫管狀態下如果長時間不適用將會在某一時刻被Java回收器回收,消亡。
1、對象直接進入Persistent狀態
1.1 get方法
從資料庫中擷取一行資訊,並將該資訊同步到建立的對象中,該方法返回一個Object對象,如果沒有查詢到內容則返回null。下面的執行個體通過採用Session的get方法來擷取一個對象,並將對象轉換為執行個體。
public void testGet1(){Session session=null;Transaction tx = null;try{session=HibernateUtils.getSession();//開啟事務tx= session.beginTransaction();//get載入上來的對象為持久對象//執行get會馬上發出查詢語句,如果不存在會返回nullUser user=(User)session.get(User.class,"ff80808145bc28cc0145bc28ce020002");System.out.println(user.getName());//persistent狀態//persistent狀態的對象,當對象的屬性發生改變的時候//Hibernate在清理緩衝(髒資料檢查)的時候,會和資料庫同步user.setName("趙柳");session.getTransaction().commit();}catch(Exception e){e.printStackTrace();if(tx != null){tx.rollback();}}finally{HibernateUtils.closeSession(session);}}
設定斷點,擷取User對象。
擷取到了該對象,通過強制轉換後得到了一個user對象。程式中添加了setName方法,也就是說會更新資料庫中的名稱,執行完成後檢查資料庫,如更新結果。
1.2 load方法
功能類似於get方法,也是從資料庫中擷取資料並同步到對象中,該方法支援lazy是一種懶漢操作,它返回的是一個持久化的Object對象或者一個代理,所以需要進行轉化。
public void testLoad1(){Session session=null;try{session=HibernateUtils.getSession();//不會馬上查詢語句,因為load支援lazy(消極式載入/懶載入)//什麼教lazy?只有真正使用這個對象的時候,再建立,對於Hibernate來說//才真正發出查詢語句,主要為了提高效能,lazy是Hibernate中非常重要的特性//Hibernate的lazy是如何?的?採用代理對象實現,代理對象主要採用的是CGLIB庫產生的//而不是JDK的動態代理,因為JDK的動態代理只能對實現了借口的類組建代理程式,CGLIB可以對類產生//代理,它採用的是繼承方式User user=(User)session.load(User.class,"8a1b653745bcc7b50145bcc7b7140001");System.out.println(user.getName());//persistent狀態//persistent狀態的對象,當對象的屬性發生改變的時候//Hibernate在清理緩衝(髒資料檢查)的時候,會和資料庫同步user.setName("zhaoliu");session.getTransaction().commit();}catch(Exception e){e.printStackTrace();}finally{HibernateUtils.closeSession(session);}}
查詢擷取該User對象如:
分析,擷取的User對象並不完整,或者說並沒有常見一個User對象,更是一種代理,它使用了CGLIB來預先載入對象,只有在使用該對象時才真正建立。
1.3 Get Vs load
get和load方法很重要,在面試Hibernate時經常會考到,下面對比下兩者。
相同點:(1)功能相同,將關係資料轉化為對象;
(2)使用方法相同,同樣需要制定兩個參數
不同點:(1)load方法支援lazy操作,預先載入對象,在使用時才建立,get是直接將關係資料轉化為對象;
(2)load載入對象如果不存在會拋出objectNotFoundException異常,get如果沒有擷取資料會返回null。
2、手動構造detached對象
想要擷取對象還有另外一種方法,它區別於get與load方法,是一種手動擷取的方法,首先常見一個對象,然後通過制定id的方式擷取該對象的資料,方法如下:
public void testUer(){Session session=null;try{session=HibernateUtils.getSession();session.beginTransaction();//手動構造detached對象User user=new User();user.setId("8a1b653745bcc7b50145bcc7b7140001");//persistent狀態//persistent狀態的對象,當對象的屬性發生改變的時候//Hibernate在清理緩衝(髒資料檢查)的時候,會和資料庫同步session.getTransaction().commit();}catch(Exception e){e.printStackTrace();}finally{HibernateUtils.closeSession(session);}}
查看擷取的結果圖:
分析結果圖,代碼中使用了setId方法為該對象制定了id號,在制定id號後就能夠對該對象進行操作,在事務提交後同步到資料庫中,採用了手動指定,手動指定了對象的資訊。
2.1 Delete方法
刪除資料庫中指定的對象,在刪除前必須將對象轉化到Persistent狀態,可以使用get、load或者手動的方法指定對象,使用方法如下代碼:
session=HibernateUtils.getSession();session.beginTransaction();User user=(User)session.load(User.class,"8a1b653745bcc6d50145bcc6d67a0001");//建議採用此種方式刪除,先載入再刪除session.delete(user);
2.2 Update
更新資料,該方法會修改資料庫中的資料。在使用的時候會出現量中情況,更新資料庫某個欄位值或者更新資料庫的整行值
2.2.1 更新某個欄位值
如果只想要更新某個欄位的值,在update前,需要使用load或者get方法使對象轉化為persistent狀態碼如下:
//擷取session對象session=HibernateUtils.getSession();//開啟事務session.beginTransaction();//或者可以使用另外的方法開啟//session.getTransaction().begin();//載入擷取User對象//方法一:使用load方法//User user=(User)session.load(User.class, "8a1b653745bcc7b50145bcc7b7140001");//方法二:手動擷取User user=new User();user.setId("8a1b653745bcc7b50145bcc7b7140001");//更新姓名user.setName("zhangsan");session.update(user);session.getTransaction().commit();
2.2.2 更新整行
想要更新整行的資料,可以採用手動將狀態轉換到detached狀態,手動指定對象的id值,代碼如下:
//擷取session對象session=HibernateUtils.getSession();//開啟事務session.beginTransaction();//或者可以使用另外的方法開啟//session.getTransaction().begin();//手動擷取User user=new User();user.setId("8a1b653745bcc7b50145bcc7b7140001");//更新姓名user.setName("zhangsan");session.update(user);session.getTransaction().commit();
查看更新結果:
分析更新結果,它其實更新了資料庫的整行資料,這種更新操作有太多的不確定因素,不建議使用。
2.3 save方法
插入資料。在執行save方法時會調用資料庫的insert語句,向資料庫中添加新的一行。save後的對象會轉化為持久態,在此狀態下的對象能夠再次更新對象,在最後提交事務時會同更改更新到資料庫。如下:
public void testSave2(){Session session=null;Transaction tx = null;try{session=HibernateUtils.getSession();//開啟事務tx= session.beginTransaction();//Transient狀態User user=new User();user.setName("zhangsi");user.setPassword("123");user.setCreateTime(new Date());user.setExpireTime(new Date());//persistent狀態//persistent狀態的對象,當對象的屬性發生改變的時候//Hibernate在清理緩衝(髒資料檢查)的時候,會和資料庫同步session.save(user);user.setName("lisi");tx.commit();}catch(Exception e){e.printStackTrace();if(tx != null){tx.rollback();}}finally{HibernateUtils.closeSession(session);}//detached狀態}
查看上例運行結果檢視:
分析結果:session在提交事務的時候其實做了兩部的操作,結合代碼中的更新過程,首先是新增了一個User對象,之後執行了save操作,它會調用insert語句,然後在代碼中做了一個setName的操作,重新修改了名稱,但這時還沒有同步到資料庫中而是在記憶體中,這時就會有兩種狀態,我們稱此時的資料位元髒資料,最後提交事務的時候更新到資料庫中。
結語
本文針對持久對象的轉化方法展開了詳細的討論,一個對象在整個生命週期中有三種狀態。文章討論至此,核心對象和持久對象的討論已經完成,核心對象構成了Hibernate的內部運行機制,持久對象是關聯式模式和物件模型進行轉化的核心。