Hibernate的狀態(tài)

一滓鸠、Hibernate三種狀態(tài)的簡介

Hibernate中的實(shí)體對象有三種狀態(tài)但惶,下面讓我來介紹一下:


1.Transient(瞬時(shí)狀態(tài))
??既沒有ID阴汇,也沒有被session管理页响。也就是剛打開session非洲,創(chuàng)建了一個(gè)類,還沒執(zhí)行save()俯画,也就是數(shù)據(jù)庫中沒有析桥。在這種狀態(tài)中的對象,并沒有被session托管艰垂,在session緩存中還不存在這個(gè)對象泡仗。

User user = new User();  
user.setUsername("ada");  
user.setPassword("123");  
user.setCreateDate(new Date());  

2.Persistent(持久化狀態(tài))
??當(dāng)執(zhí)行了save、update等操作之后猜憎,這個(gè)對象就會被session所管理娩怎,被管理之后就稱為Persistent。如果對象處于持久態(tài)胰柑,那么在session的緩沖中會存著一份該對象的拷貝截亦,這份拷貝被session所管理爬泥。

//當(dāng)執(zhí)行完save之后會被session管理
session.save(u);
//當(dāng)被session所管理之后,只要該對象的值被修改并且在事務(wù)提交時(shí)會自動將值完成修改
u.setAge(18);
//此處沒有調(diào)用update但是user也會調(diào)用一條update語句完成修改
//這個(gè)時(shí)候用save崩瓤、update方法都是沒有意義的
session.getTransaction().commit();

所以我們要記住一點(diǎn):如果一個(gè)對象是持久態(tài)的話袍啡,那么此時(shí)對對象進(jìn)行各種修改,或者調(diào)用多次update谷遂、save方法葬馋,hibernate都不會發(fā)送sql語句。只有當(dāng)事務(wù)提交時(shí)肾扰,此時(shí)hibernate才會拿當(dāng)前這個(gè)對象與之前保存在session中的持久化對象進(jìn)行比較畴嘶,如果不相同就發(fā)送一條update的sql語句,否則就不會發(fā)送update語句集晚。
??當(dāng)session調(diào)用get窗悯、load方法時(shí),如果數(shù)據(jù)庫中有該對象偷拔,則該對象也會變成一個(gè)持久化對象蒋院,被session所托管。因此莲绰,這個(gè)時(shí)候如果對對象進(jìn)行操作欺旧,在提交事務(wù)時(shí)同樣會去與session中的持久化對象進(jìn)行比較。

session = HibernateUtil.openSession();
session.beginTransaction();
 //此時(shí)u是Persistent
User u = (User)session.load(User.class, 4);
//由于u這個(gè)對象和session中的對象不一致蛤签,所以會發(fā)出sql完成更新
session.getTransaction().commit();

特別注意辞友,如果我們想要修改一個(gè)持久化對象的主鍵的話,就會報(bào)錯(cuò)震肮,下面看一個(gè)栗子:

session.beginTransaction();
User u = new User();
 u.setId(5);
 //完成update之后也會變成持久化狀態(tài)
session.update(u); 
u.setPassword("lisi");
u.setUsername("lisi");
//會拋出異常
u.setId(333);
session.getTransaction().commit();

這個(gè)時(shí)候称龙,hibernate會報(bào)錯(cuò),因?yàn)槲覀兊膗當(dāng)前已經(jīng)是一個(gè)持久化對象戳晌,如果試圖修改一個(gè)持久化對象的主鍵的值的話鲫尊,就會拋出異常,這點(diǎn)要特別注意沦偎。

org.hibernate.HibernateException: identifier of an instance of com.xiaoluo.bean.User was altered from 5 to 333

3.Detached(離線狀態(tài))
??離線狀態(tài)指數(shù)據(jù)庫中存在但是沒有被session所管理疫向。

User user = new User();  
user.setUsername("ada");  
user.setPassword("123");  
user.setCreateDate(new Date());  
//當(dāng)我們進(jìn)行了user.setId(11)后,u就變成了離線狀態(tài)
//因?yàn)閿?shù)據(jù)庫中存在id=11的這個(gè)對象豪嚎,但是該對象又沒有被session所托管
user.setId(11);
session.save(u);

要注意鸿捧,對于離線狀態(tài)的對象執(zhí)行save時(shí)會忽略狀態(tài)而直接進(jìn)行insert操作,當(dāng)save一執(zhí)行的時(shí)候疙渣,此時(shí)hibernate會根據(jù)id的生成策略往數(shù)據(jù)庫中再插入一條數(shù)據(jù):

Hibernate: insert into t_user (username, password, createDate) values (?, ?, ?)

所以對于離線對象,如果要使其變成持久化對象的話堆巧,我們不能使用save方法妄荔,而應(yīng)該使用update方法泼菌。方法如下:

User user = new User();  
user.setUsername("ada");  
user.setPassword("123");  
user.setCreateDate(new Date());  
user.setId(11);
session.update(u);

當(dāng)調(diào)用了update方法以后,u已經(jīng)變成了一個(gè)持久化的對象啦租,那么如果此時(shí)對u對象進(jìn)行修改操作后哗伯,在事務(wù)提交的時(shí)候,則會拿該對象和session中剛保存的持久化對象進(jìn)行比較篷角,如果不同就發(fā)一條sql語句:

Hibernate: update t_user set username=?, password=?, createDate=? where id=?

還有另外一種方法就是使用saveOrUpdate()焊刹,這個(gè)方法會執(zhí)行這樣的操作:如果是離線對象就執(zhí)行update,如果是瞬時(shí)對象就執(zhí)行insert恳蹲。但是這個(gè)方法一般不會使用虐块。

二、狀態(tài)之間的轉(zhuǎn)換

1.當(dāng)我們調(diào)用session.delete()的操作之后嘉蕾,對象就會從持久態(tài)/離線態(tài)變成瞬時(shí)態(tài)贺奠,因?yàn)榇藭r(shí)數(shù)據(jù)庫不存在該對象了。此時(shí)我們再對該對象進(jìn)行各種修改操作的話错忱,hibernate也不會發(fā)送任何修改語句

session = HibernateUtil.openSession();
session.beginTransaction();
User u = new User();
//此時(shí)u為detached對象
u.setId(5);
//此時(shí)u為transient對象
session.delete(u);
//此時(shí)u已經(jīng)是瞬時(shí)對象儡率,不會被session和數(shù)據(jù)庫所管理
u.setPassword("wangwu");
session.getTransaction().commit();

2.當(dāng)我們調(diào)用close()方法后,會把一個(gè)持久態(tài)對象轉(zhuǎn)化為離線態(tài)對象以清。

    session.save(u);
    //目前u是持久態(tài)對象
    session.getTransaction().commit();
}catch(HibernateException e){
    session.getTransaction().rollback();
}finally{
    //注意在這個(gè)步驟中儿普,session已經(jīng)被關(guān)閉了
    if(session!=null)
       session.close();
}
Session session2 = null;
session2 = HibernateUtil.openSession();
session2.beginTransaction();
//目前u就是一個(gè)離線態(tài)的對象
System.out.println(u.getId());
u.setAge(18);
//對于離線對象而言,當(dāng)調(diào)整了這個(gè)對象的狀態(tài)時(shí)只要不在同一個(gè)session中是不會完成更新的
session2.getTransaction().commit();

u.setAge(18);
//執(zhí)行完update之后又變成持久化狀態(tài)掷倔,又會被session所管理
session2.update(u);
session2.getTransaction().commit();

3.當(dāng)我們調(diào)用session.clear()方法眉孩,這個(gè)時(shí)候就會將session的緩存對象清空,那么session中就沒有了user這個(gè)對象今魔,此時(shí)對象就會從持久態(tài)變成離線態(tài)勺像。這個(gè)時(shí)候提交事務(wù),發(fā)現(xiàn)session中已經(jīng)沒有該對象错森,所以不會進(jìn)行任何操作吟宦。

session = HibernateUtil.openSession();
session.beginTransaction();
//此時(shí)u是Persistent
User u = (User)session.load(User.class, 4);
u.setUsername("123");
//清空session
session.clear();
//不會進(jìn)行update,因?yàn)閟ession已經(jīng)被清空
session.getTransaction().commit();

里只會發(fā)送一條select語句:

Hibernate: select user0_.id as id0_0_, user0_.createDate as createDate0_0_, user0_.password as password0_0_, user0_.username as username0_0_ from t_user user0_ where user0_.id=?

三涩维、merge方法

一個(gè)session不能管理兩個(gè)相同的對象殃姓,此時(shí)我們可以用merge合并對象。這個(gè)方法的作用就是解決一個(gè)持久化對象兩份拷貝的問題瓦阐,這個(gè)方法會將兩個(gè)對象合并在一起成為一個(gè)對象蜗侈。

session = HibernateUtil.openSession();
session.beginTransaction();
//u1已經(jīng)是持久化狀態(tài)
User u1 = (User)session.load(User.class, 3);
//u2是離線狀態(tài)
User u2 = new User();
u2.setId(3);
u2.setPassword("123456789");
//此時(shí)u2將會變成持久化狀態(tài),在session的緩存中就存在了兩份同樣的對象,在session中不能存在兩份拷貝睡蟋,否則會拋出異常
//session.saveOrUpdate(u2);
//merge方法會判斷session中是否已經(jīng)存在同一個(gè)對象踏幻,如果存在就將兩個(gè)對象合并
session.merge(u2);
//最佳實(shí)踐:merge一般不用
session.getTransaction().commit();

調(diào)用了merge方法以后,此時(shí)會將session中的兩個(gè)持久化對象合并為一個(gè)對象戳杀,但是merge方法不建議被使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末该面,一起剝皮案震驚了整個(gè)濱河市夭苗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隔缀,老刑警劉巖题造,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異猾瘸,居然都是意外死亡界赔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門牵触,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淮悼,“玉大人,你說我怎么就攤上這事荒吏×簿” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵绰更,是天一觀的道長瞧挤。 經(jīng)常有香客問我,道長儡湾,這世上最難降的妖魔是什么特恬? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮徐钠,結(jié)果婚禮上癌刽,老公的妹妹穿的比我還像新娘。我一直安慰自己尝丐,他們只是感情好显拜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爹袁,像睡著了一般远荠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上失息,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天譬淳,我揣著相機(jī)與錄音,去河邊找鬼盹兢。 笑死邻梆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绎秒。 我是一名探鬼主播浦妄,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了剂娄?” 一聲冷哼從身側(cè)響起窘问,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宜咒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體把鉴,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡故黑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庭砍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片场晶。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怠缸,靈堂內(nèi)的尸體忽然破棺而出诗轻,到底是詐尸還是另有隱情,我是刑警寧澤揭北,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布扳炬,位于F島的核電站,受9級特大地震影響搔体,放射性物質(zhì)發(fā)生泄漏恨樟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一疚俱、第九天 我趴在偏房一處隱蔽的房頂上張望劝术。 院中可真熱鬧,春花似錦呆奕、人聲如沸养晋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绳泉。三九已至,卻和暖如春陈轿,著一層夾襖步出監(jiān)牢的瞬間圈纺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工麦射, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛾娶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓潜秋,卻偏偏與公主長得像蛔琅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子峻呛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容