標籤:style blog class code java ext
上篇文章討論了Hibernate的核心對象,在開發過程中經常用到的有JTA、SessionFactory、Session、JDBC,其中SessionFactory可以看做資料庫的鏡像,使用它能夠建立Session對象,JTA用來管理事務,在物件模型修改後同步到資料庫中,另外還有Hibernate作為持久層它封裝了持久層的轉化過程,下面著重討論持久對象的轉換過程。
一、狀態解析
Hibernate的持久對象主要分為三個狀態,Transient、Persistent、Detached,其中Transient稱為瞬態,沒有被資料庫管理,Hibernate沒有為對象分配id,在資料庫中沒有對應的行,一般在new出一個對象後轉化為瞬態;Persistent稱為持久化,此時已經被Session管理,Hibernate為對象分配了一個id(該id可以使用其它方法手動或者自動分配,id的類型可以在User.hbm.xml中配置),在資料庫中已經有了對應的一行,在調用session的save方法後會提交到資料庫中;Detached稱為脫管對象,此時已經將修改同步到了資料庫中,它有Hibernate分配的id,但是此時的id是在持久化狀態分配的,在編程時此狀態的對象往往已經不受session管理,如果想要再次修改可以再次建立一個session,然後管理對象。Transient、Detached的對象如果長時間不使用的話,會在某一時間段被Java的記憶體回收裝置進行回收。
1、Transient:資料庫中沒有,沒有被Session管理
從Hibernate的體繫結構圖中不難看出,對象的瞬態是在應用程式中完成的,當對象被建立後即轉變為瞬態,它還沒有持久化的過程,也就是說並沒有持久化標示(id號,Hibernate在建立持久化對象時都會為該對象指定一個id標示,保證唯一性)。瞬態的對象如果沒有任何的操作的話,會在某一時刻消亡,並被Java的記憶體回收行程回收。
案例示範:在SessionTest中添加一個名為testSave1的方法,代碼如下:
public void testSave1(){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());}catch(Exception e){e.printStackTrace();if(tx != null){tx.rollback();}}finally{HibernateUtils.closeSession(session);}//detached狀態}
在save方法處設定斷點,運行調試,輸出結果如:
2、Persistent:資料庫中有,被session管理
一個瞬態的對象操作完成後需要儲存操作,這時候調用save或者其他儲存方法時即被轉換為持久對象,這時候Hibernate給該對象建立一個持久化標示,並且可能在資料庫中有了一個對應行,而且該標示與Java標示(該值表示對象在記憶體的位置)等價。 另外一個沒有被建立的對象同樣可以使用其它的方法來直接轉換到該狀態,如的get、load等方法。persistent狀態的對象若發生了改變,則在清理記憶體時或者在髒資料檢查時會把改變同步到資料庫中,那麼此時會產生兩條語句,分別為insert和update。在SessionTest中添加saveTest2方法,測試持久態
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");//可以顯示的調用udpdate方法,因為此時為持久狀態,調用udpate沒有什麼意義session.update(user);tx.commit();}catch(Exception e){e.printStackTrace();if(tx != null){tx.rollback();}}finally{HibernateUtils.closeSession(session);}
}
調用save方法後進入的持久態,此時的為user對象添加了id標識: 方法執行完成後會向資料庫中添加新的一條資訊,細心的童鞋可以看出方法中調用了兩次setName方法,最後結果是什麼呢,查看mysql中的表可以看到:
資料庫中添加的最後資訊是lisi,所以它最後執行了更新操作,此時在控制台中會列印兩條sql語句,分別為insert和update語句。
Note:在提交事務或者關閉Session前,會調用Session的flush方法對每個更改進行操作。
3、Detached:資料庫中有,沒有被session管理
脫管狀態下的對象其實已經被映射到了資料庫中,只不過此時還沒有被記憶體回收期回收,此時的對象擁有持久化標識,該標識對應著資料庫中的一行,但是不保證該標識與Java標識對應。
在SessionTest類中添加testSave3方法,測試Detached狀態下對象和資料庫,代碼如下:
public void testSave3(){Session session=null;Transaction tx = null;User user=null;try{session=HibernateUtils.getSession();//開啟事務tx= session.beginTransaction();//Transient狀態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狀態user.setName("wangwu");try{session=HibernateUtils.getSession();session.beginTransaction();//將detached狀態的對象重新納入session管理//此時將變為persistent狀態的對象//persistent狀態的對象,在清理緩衝時會和資料庫同步session.update(user);session.getTransaction().commit();}catch(Exception e){e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}
執行完成後,查看資料庫中資訊,如:
分析執行結果,不難發現它最後完成的是更新操作,不同的是detached狀態下的對象必須重新定義新的Session對象,因為Session對象線程不安全,容易出錯。
結語
上文主要討論分析了Hibernate持久對象在整個聲明周期的狀態轉化過程,這幾種狀態的相互轉化使得關聯式模式和物件模型進行了緊密的關聯,另外在使用設定檔來管理這幾種狀態,這樣使得Hibernate的操作簡單,並且功能強大。上文只是針對持久對象的幾種狀態做了初步的解析,另外還有狀態之間的轉化方法將會在下篇文章討論。