深入學習Hibernate持久化對象的三個狀態(tài)
Hibernate中的對象有3中狀態(tài),瞬時對象(TransientObjects)、持久化對象(PersistentObjects)和離線對象(DetachedObjects也叫做脫管對象)。
下圖3.1顯示了瞬時對象、持久化對象和離線對象之間的關(guān)系以及它們之間的轉(zhuǎn)換。

圖3.1
臨時狀態(tài):由Java的new命令開辟內(nèi)存空間的java對象也就是普通的java對象,如果沒有變量引用它它將會被JVM收回。臨時對象在內(nèi)存中是孤立存在的,它的意義是攜帶信息載體,不和數(shù)據(jù)庫中的數(shù)據(jù)由任何的關(guān)聯(lián)。通過Session的save()方法和saveOrUpdate()方法可以把一個臨時對象和數(shù)據(jù)庫相關(guān)聯(lián),并把臨時對象攜帶的信息通過配置文件所做的映射插入數(shù)據(jù)庫中,這個臨時對象就成為持久化對象。
持久化狀態(tài):持久化對象在數(shù)據(jù)庫中有相應的記錄,持久化對象可以是剛被保存的,或者剛被加載的,但都是在相關(guān)聯(lián)的session聲明周期中保存這個狀態(tài)。如果是直接數(shù)據(jù)庫查詢所返回的數(shù)據(jù)對象,則這些對象和數(shù)據(jù)庫中的字段相關(guān)聯(lián),具有相同的id,它們馬上變成持久化對象。如果一個臨時對象被持久化對象引用,也立馬變?yōu)槌志没瘜ο蟆?br /> 如果使用delete()方法,持久化對象變?yōu)榕R時對象,并且刪除數(shù)據(jù)庫中相應的記錄,這個對象不再與數(shù)據(jù)庫有任何的聯(lián)系。
持久化對象總是與Session和Transaction關(guān)聯(lián)在一起,在一個session中,對持久化對象的操作不會立即寫到數(shù)據(jù)庫,只有當Transaction(事務)結(jié)束時,才真正的對數(shù)據(jù)庫更新,從而完成持久化對象和數(shù)據(jù)庫的同步。在同步之前的持久化對象成為臟對象。
當一個session()執(zhí)行close()、clear()、或evict()之后,持久化對象就變?yōu)殡x線對象,這時對象的id雖然擁有數(shù)據(jù)庫的識別值,但已經(jīng)不在Hibernate持久層的管理下,他和臨時對象基本上一樣的,只不過比臨時對象多了數(shù)據(jù)庫標識id。沒有任何變量引用時,jvm將其回收。
脫管狀態(tài):Session關(guān)閉之后,與此Session關(guān)聯(lián)的持久化對象就變成為脫管對象,可以繼續(xù)對這個對象進行修改,如果脫管對象被重新關(guān)聯(lián)到某個新的Session上,會在此轉(zhuǎn)成持久對象。
脫管對象雖然擁有用戶的標識id,所以通過update()、saveOrUpdate()等方法,再次與持久層關(guān)聯(lián)。
下面我們就通過使用hibernate,實現(xiàn)對數(shù)據(jù)庫的增刪改查來體現(xiàn)三種狀態(tài)之間的轉(zhuǎn)換過程。
添加修改演示三種狀態(tài)之間的變化
當我們建立Session都要實例化SessionFactory,所以我們把重復的代碼進行封裝,并且session是單線程的。我們把對session的管理,打開session,關(guān)閉session等封裝到工具類中,代碼如下所示。
package com.bjpowernode.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
//static只初始化一次.
static
{
try{
//默認讀取的是hibernate.cfg.xml 文件.
Configuration cfg = new Configuration().configure();
//建立SessionFactory.
factory = cfg.buildSessionFactory();
}catch(Exception e )
{
e.printStackTrace();
}
}
public static Session getSession()
{
//打開session.
return factory.openSession();
}
//關(guān)閉session.
public static void closeSession(Session session)
{
//判斷是否為空.
//判斷是否是打開狀態(tài)再進行關(guān)閉.
if(session!=null)
{
if(session.isOpen())
{
session.close();
}
}
}
//返回工廠類.
public static SessionFactory getSessionFactory()
{
return factory;
}
}
Hibernate.cfg.xml代碼如下所示。
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory > <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/Hibernate_session</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.show_sql">true</property> <mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/> </session-factory> </hibernate-configuration>
之前我們把對表添加的操作放到普通的java類中,在這個類的main()方法中執(zhí)行,如果我們再對表進行其他的操作呢?那是不是還要建立新的java類,多個方法就不容易測試了。我們使用測試工具類JUnit來做測試,來測試增刪改查。首先建立源目錄,在test包中放測試程序。
我們建立我們的測試程序SessionTest.java,繼承TestCase類,這樣我們在SessionTest.java類中測試數(shù)據(jù)庫中的某個方法,方法名的規(guī)范要以test開頭。我們向User表中添加一條記錄如下代碼所示。
package com.bjpowernode.hibernate;
import java.util.Date;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class SessionTest extends TestCase {
//測試方法以test開頭.
public void testSave1()
{
Session session = null;
Transaction tx = null;
try
{
//取得session.
session = HibernateUtils.getSession();
//自己開啟事務. 返回 transient的一個實例.
tx = session.beginTransaction();
//傳入值.變?yōu)門ransient狀態(tài).
User user = new User();
user.setName("張三");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//進行保存.執(zhí)行save則對session進行管理了. 處于持久狀態(tài).
//persistent狀態(tài)的對象.當對象的屬性發(fā)生改變的時候,hibernate在清理
//緩存的時候(臟數(shù)據(jù)檢查)的時候,會和數(shù)據(jù)庫同步.
session.save(user);
user.setName("李四");
//再次提交.
tx.commit();
}catch(Exception e)
{
e.printStackTrace();
if(tx!=null)
{
// 事務回滾.
tx.rollback();
}
}finally
{
//關(guān)閉session.當關(guān)閉session時處于Detached狀態(tài).
HibernateUtils.closeSession(session);
}
}
首先是建立對象與表的會話session,開啟事務session.beginTransaction(),實例化User對象,當我們User user = new User()的時候,當我們new一個對象的時候數(shù)據(jù)庫是沒有的,所以是Transient對象(臨時對象),然后給user賦值,設(shè)置名稱和密碼以及其他屬性。 為對象的所有屬性賦值完畢,接下來保存到會話session中,拿到session執(zhí)行save(user)方法。 當我們執(zhí)行session的save()方法時,這個對象就被session管理了,session中有個map,會把對象放到map中,此時的對象我們就成為persistent狀態(tài)(持久狀態(tài))。
接下來我們又把user中的name屬性設(shè)置為“李四”,之后提交事務。我們先再會話中存儲的“張三”,之后改為“李四”。try catch來撲捉異常,當執(zhí)行完畢,關(guān)閉session后,對象處于detached狀態(tài)(離線狀態(tài))。
我們創(chuàng)建數(shù)據(jù)庫,利用ExportDB.java方法建立表。之后執(zhí)行SessionTest的testSave1()方法,當執(zhí)行到session方法的時候,表中自動生成user表的id值,并且名子為“張三”,之后再次執(zhí)行,名字又變?yōu)椤袄钏摹?,之后?zhí)行事務的commit()方法tx .commit ,此時控制臺才發(fā)出語句,如下圖3.2。

從控制臺的語句中可以看出,顯示發(fā)送的插入sql語句,后是update語句,首先是持久化對象user中的名字為“張三”,所以save的時候生成inset語句。此時user處于持久狀態(tài)的對象,我們之后又給變了持久化對象,所以發(fā)送了一個修改語句。也就是當持久化對象發(fā)生修改時,我們再提交事務,就會把修改的全部體現(xiàn)出來(update語句)。
也就是我們再提交事務的時候,在清理緩存,也就是臟數(shù)據(jù)檢查(內(nèi)存中變了,而數(shù)據(jù)沒變),要檢查哪些數(shù)據(jù)是有問題的,要保持內(nèi)存和數(shù)據(jù)庫的同步。所以我們數(shù)據(jù)庫中添加的記錄,user的名字為李四(如圖3.3所示)。

圖3.3
如果上述代碼中,我們在修改名字為李四后user.setName("李四");我們顯示調(diào)用session的update()方法,session.update(),運行,會看到控制臺上打印的sql語句和我們不加如session.update()打印的相同。持久化對象只要更改了,在提交事務的時候就會同步,沒有必要再顯示調(diào)用。
Detached狀態(tài)演示
我們在執(zhí)行完所有的操作,關(guān)閉session后,此時的user對象變?yōu)閐etached狀態(tài),此時進行操作。
代碼如下所示。
public void testSave3()
{
Session session = null;
Transaction tx = null;
User user = null;
try
{
//取得session.
session = HibernateUtils.getSession();
//自己開啟事務. fanhui transient的一個實例.
tx = session.beginTransaction();
//傳入值.變?yōu)門ransient狀態(tài).
user = new User();
user.setName("張三");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//進行保存.執(zhí)行save則對session進行管理了. 處于持久狀態(tài).
//persistent狀態(tài)的對象.當對象的屬性發(fā)生改變的時候,hibernate在清理
//緩存的時候(臟數(shù)據(jù)檢查)的時候,會和數(shù)據(jù)庫同步.
session.save(user);
user.setName("李四");
//可以顯示的調(diào)用update方法,因為此時為持久狀態(tài),調(diào)用update沒有什么意義.
//再次提交.
tx.commit();
}catch(Exception e)
{
e.printStackTrace();
if(tx!=null)
{
// 事務回滾.
tx.rollback();
}
}finally
{
//關(guān)閉session.當關(guān)閉session時處于Detached狀態(tài).
HibernateUtils.closeSession(session);
}
//已經(jīng)不能用以前的session了.
user.setName("王五");
try
{
//得到新的session.
session = HibernateUtils.getSession();
//開啟事務.
session.beginTransaction();
//將detached狀態(tài)的對象重新納入session管理.
//此時將變?yōu)閜ersistent狀態(tài)的對象.
//persistent狀態(tài)的對象,在清理緩存時,會根數(shù)據(jù)庫同步.
session.update(user);
//提交事務.把內(nèi)存的改變提交到數(shù)據(jù)庫上.
session.getTransaction().commit();
}catch(Exception e)
{
e.printStackTrace();
session.getTransaction().rollback();
}finally
{
HibernateUtils.closeSession(session);
}
}
取得detached狀態(tài)的user對象,改變這個對象的name值,user.setName("王五");之后我們再new一個新的
session,通過session開啟事務,之后更新操作,session.update(user),也就是把離線的對象(或脫管對象)再納入session管理,這樣就會和數(shù)據(jù)庫同步,因為session.update()就把user對象納入session管理,user對象由離線狀態(tài)變?yōu)閜ersistent狀態(tài)。
提交事務,將和數(shù)據(jù)庫同步。把內(nèi)存的改變體現(xiàn)到數(shù)據(jù)庫上??刂婆_sql語句以及運行向表中添加記錄結(jié)果如圖3.4,3.5所示。

圖3.4

總結(jié)
以上所述是小編給大家介紹的Hibernate持久化對象的三個狀態(tài),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
IntelliJ IDEA打開多個Maven的module且相互調(diào)用代碼的方法
這篇文章主要介紹了IntelliJ IDEA打開多個Maven的module且相互調(diào)用代碼的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02
java springboot郵箱找回密碼功能的實現(xiàn)講解
這篇文章主要介紹了java springboot郵箱找回密碼功能的實現(xiàn)講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
mybatis如何使用注解實現(xiàn)一對多關(guān)聯(lián)查詢
這篇文章主要介紹了mybatis如何使用注解實現(xiàn)一對多關(guān)聯(lián)查詢的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
JavaSwing基礎(chǔ)之Layout布局相關(guān)知識詳解
上次我們說到View的Mearsure流程,今天接著說說layout. 關(guān)于layout,很多朋友知道它是負責布局的,那么具體是怎么布局的?viewGroup和view的layout方法又有什么不同?一起來看看吧,需要的朋友可以參考下2021-05-05
Eclipse中實現(xiàn)JS代碼提示功能(圖文教程)
本文通過圖文并茂的形式給大家介紹了Eclipse中實現(xiàn)JS代碼提示功能,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-11-11
java實現(xiàn)將ftp和http的文件直接傳送到hdfs
前面幾篇文章,我們已經(jīng)做了很好的鋪墊了,幾個要用到的工具我們都做了出來,本文就是將他們集合起來,說下具體的用法,小伙伴們可以參考下。2015-03-03

