Hibernate_2_Hibernate中对象状态及转化_一级缓存_Session详解_HQL/SQL/Criteria_一对多关系_级联操作
Hibernate中的對(duì)象狀態(tài)
在Hibernate中持久化對(duì)象具有三種狀態(tài): 瞬時(shí)態(tài), 持久態(tài), 游離態(tài).
瞬時(shí)態(tài): 對(duì)象沒有與Hibernate產(chǎn)生關(guān)聯(lián)(transient,session中沒有緩存), 數(shù)據(jù)庫(kù)中也沒有對(duì)應(yīng)記錄=> 對(duì)象無id, 沒有關(guān)聯(lián) 持久態(tài): 對(duì)象與Hibernate產(chǎn)生關(guān)聯(lián)(persistent, session中有緩存), 數(shù)據(jù)庫(kù)中會(huì)存在記錄=> 對(duì)象存有id, 有關(guān)聯(lián) 游離態(tài): 對(duì)象沒有與Hibernate產(chǎn)生關(guān)聯(lián)(detached,session中沒有緩存), 數(shù)據(jù)庫(kù)中有記錄=> 對(duì)象有id, 沒有關(guān)聯(lián)持久化對(duì)象狀態(tài)之間的相互轉(zhuǎn)化
- 瞬時(shí)(無id, 無關(guān)聯(lián))=>持久(有id, 有關(guān)聯(lián)) save操作:
修改id, 與session的關(guān)聯(lián)狀態(tài)
注: 只有Hibernate的主鍵生成策略變?yōu)閍ssigned才能手動(dòng)設(shè)置id, 否則報(bào)錯(cuò)
- **瞬時(shí)(無id, 無關(guān)聯(lián))=>游離(有id, 無關(guān)聯(lián)) **
修改id即可
- 持久(有id, 有關(guān)聯(lián))=>瞬時(shí)(無id, 無關(guān)聯(lián))
修改id與關(guān)聯(lián)狀態(tài)即可
- 持久(有id, 有關(guān)聯(lián))=>游離(有id, 無關(guān)聯(lián))
獲得持久對(duì)象, 然后切斷持久對(duì)象與session的聯(lián)系
- 游離(有id, 無關(guān)聯(lián))=>瞬時(shí)(無id, 無關(guān)聯(lián))
設(shè)置游離對(duì)象id為null
- 游離(有id, 無關(guān)聯(lián))=>持久(有id, 有關(guān)聯(lián))
重新將游離對(duì)象寫入數(shù)據(jù)庫(kù), 使得與session產(chǎn)生聯(lián)系
注: 持久態(tài)的時(shí)候不允許修改持久化對(duì)象的id: u.setId(2), 修改直接報(bào)錯(cuò), 對(duì)持久化對(duì)象直接進(jìn)行修改:u.setName(“C”), 那么Hibernate將會(huì)執(zhí)行update操作, 將修改的持久化對(duì)象的數(shù)據(jù)同步到數(shù)據(jù)庫(kù)
一級(jí)緩存
一級(jí)緩存(session緩存), 用于存儲(chǔ)持久化對(duì)象 , 內(nèi)部?jī)?chǔ)存結(jié)構(gòu)是一個(gè)Map, 當(dāng)需要使用持久化對(duì)象的時(shí)候, Hibernate會(huì)優(yōu)先從緩存中獲取, 當(dāng)session關(guān)閉, 一級(jí)緩存銷毀.
- 快照
快照: 緩存的復(fù)制品, 存放在session中
快照主要用來與緩存中數(shù)據(jù)進(jìn)行比較, 判斷緩存中數(shù)據(jù)是否發(fā)生變化
- 緩存執(zhí)行過程:
- 緩存刷新時(shí)機(jī):
- 緩存導(dǎo)致的問題:
每次獲取持久化對(duì)象, Hibernate優(yōu)先去緩存中查找, 一定程度上提高了SQL的執(zhí)行效率.
緩存的存在, 出現(xiàn)的一個(gè)問題就是: 如果Hibernate獲得持久化對(duì)象后, 數(shù)據(jù)庫(kù)中數(shù)據(jù)又出現(xiàn)了修改, 當(dāng)再次對(duì)該持久化對(duì)象進(jìn)行操作的時(shí)候, Hibernate會(huì)優(yōu)先從緩存中獲得持久化對(duì)象, 導(dǎo)致數(shù)據(jù)庫(kù)與Hibernate中數(shù)據(jù)不一致. 當(dāng)出現(xiàn)這種問題的時(shí)候, 建議JDBC操作
注: 避免將相同的對(duì)象放入緩存中, 謹(jǐn)記緩存是一個(gè)Map, 看如下操作:
User u1 = session.get(User.class, 1);//緩存中放入u1 session.evict(u1);//變?yōu)橛坞x態(tài), 緩存中不存在 User u2 = session.get(User.class, 1);//獲得id=1的持久化對(duì)象,緩存中存在 session.update(u1);//u1重新變?yōu)槌志脩B(tài), 緩存中存在 //u1, u2同時(shí)存在緩存中, 將會(huì)報(bào)錯(cuò)session緩存常用API
- evict(Object o): 將指定對(duì)象從session緩存中移除
- clear(): 清除session緩存中所有的對(duì)象
- refresh(Object o):
強(qiáng)制刷新指定對(duì)象, 使持久化對(duì)象數(shù)據(jù)與數(shù)據(jù)庫(kù)中數(shù)據(jù)一致, 一定程度上避免session緩存產(chǎn)生的數(shù)據(jù)不一致問題;
對(duì)o對(duì)象重新執(zhí)行SQL - flush():
對(duì)比快照與緩存中的數(shù)據(jù), 確保數(shù)據(jù)一致, 然后將緩存中數(shù)據(jù)提交到數(shù)據(jù)庫(kù), 類似于commit, 數(shù)據(jù)不一致的時(shí)候刷新緩存中的數(shù)據(jù)
對(duì)象的操作
- save操作細(xì)節(jié):
當(dāng)執(zhí)行save的時(shí)候, 對(duì)象會(huì)從瞬時(shí)態(tài)=>持久態(tài), 事務(wù)提交后將持久化對(duì)象存入數(shù)據(jù)庫(kù)中
- persist操作:
persist操作與save一樣, 他們二者的區(qū)別在: persist會(huì)檢查對(duì)象主鍵, save不會(huì)檢查對(duì)象主鍵
例如:
- update操作細(xì)節(jié):
游離對(duì)象=>持久對(duì)象, 對(duì)持久對(duì)象屬性修改后, 使用save, 執(zhí)行的是update, 而非insert
在映射文件的class標(biāo)簽中設(shè)置select-before-update=“true”, 那么執(zhí)行update就會(huì)執(zhí)行如下操作:
- saveOrUpdate:
該方法就是save與update的結(jié)合, session.saveOrUpdate(u); 如果u存在id, 那么執(zhí)行select, 然后再執(zhí)行update, 沒有id, 執(zhí)行insert
HQL, SQL, Criteria與緩存的聯(lián)系
下面通過例子說明:
體現(xiàn)一個(gè)問題: HQL都會(huì)執(zhí)行select操作,將獲取的list與緩存中的數(shù)據(jù)進(jìn)行比較//如果相同, 每次獲取緩存中的封裝對(duì)象/*List<User> list1 = session.createQuery("from User").list();List<User> list2 = session.createQuery("from User").list();List<User> list3 = session.createQuery("from User").list();for(User u:list1){System.out.println(u);}System.out.println(list1.hashCode()+"--"+list2.hashCode()+"--"+list3.hashCode());*///原生的SQL操作與HQL一致/*List<User> list1 = session.createSQLQuery("select * from t_User").addEntity(User.class).list();List<User> list2 = session.createSQLQuery("select * from t_User").addEntity(User.class).list();List<User> list3 = session.createSQLQuery("select * from t_User").addEntity(User.class).list();for(User u:list1){System.out.println(u);}System.out.println(list1.hashCode()+"--"+list2.hashCode()+"--"+list3.hashCode());*///criteria操作同上/*List<User> list1 = session.createCriteria(User.class).list();List<User> list2 = session.createCriteria(User.class).list();List<User> list3 = session.createCriteria(User.class).list();for(User u:list1){System.out.println(u);}System.out.println(list1.hashCode()+"--"+list2.hashCode()+"--"+list3.hashCode());*/通過程序的運(yùn)行觀察執(zhí)行的SQL語句, 以及l(fā)ist對(duì)象的hashCode, 發(fā)現(xiàn)每次執(zhí)行批量查詢(HQL, SQL, Criteria)都會(huì)select * from t_user, 然后將查詢的結(jié)果集與Session緩存中的數(shù)據(jù)進(jìn)行比較.
說明:Hibernate把第一次執(zhí)行的結(jié)果集放入緩存區(qū), 在后面的查詢中, 盡管Hibernate發(fā)送了SQL語句, 但是使用的數(shù)據(jù)依舊是緩存中的數(shù)據(jù), 這個(gè)時(shí)候使用get操作的時(shí)候, 獲取的數(shù)據(jù)也是從緩存區(qū)中得到
多表設(shè)計(jì)
表中存在的三種關(guān)系: 多對(duì)多, 一對(duì)多, 一對(duì)一
-
數(shù)據(jù)庫(kù)描述上述關(guān)系:
在數(shù)據(jù)庫(kù)中所有的關(guān)系都需要通過外鍵進(jìn)行約束. -
Bean對(duì)象描述上述的關(guān)系:
Hibernate的一對(duì)多關(guān)系實(shí)現(xiàn)
一對(duì)多操作的時(shí)候, 維護(hù)一個(gè)對(duì)象的時(shí)候會(huì)自動(dòng)維護(hù)另一方的關(guān)系; 例如 Customer referenced Order, 當(dāng)刪除Order的時(shí)候,Hibernate會(huì)先update商品表中所有的外鍵為null, 然后再執(zhí)行刪除訂單操作, 我們就不用顯式修改商品表中的外鍵, 維護(hù)商品與訂單之間的關(guān)系
測(cè)試類:
//消費(fèi)者: public class Customer {private Integer cid;private String cname;private Set<Order> orderSet = new HashSet<Order>();//get/set方法就不寫了 } //訂單 public class Order {private Integer oid;private String price;private Customer customer;//get/set方法就不寫了 }- Customer.hbm.xml與Order.hbm.xml編寫
在Customer.hbm.xml中:
set標(biāo)簽用于確定容器(用于裝備Order)name屬性: 確定對(duì)象屬性名cascade屬性: 設(shè)置Customer與Order的級(jí)聯(lián)操作inverse屬性: 將關(guān)系的維護(hù)翻轉(zhuǎn)給對(duì)方, 默認(rèn)值false(我維護(hù)這個(gè)關(guān)系)key標(biāo)簽確定Customer主鍵名one-to-many標(biāo)簽確定從表Ordercascade詳細(xì)級(jí)聯(lián)操作: 級(jí)聯(lián)操作就是, 當(dāng)A與B綁定好關(guān)系后, 就比如Customer的set已經(jīng)存儲(chǔ)了B, 當(dāng)A執(zhí)行save的時(shí)候, B也會(huì)自動(dòng)執(zhí)行save操作, 少寫session.save(B)的代碼, 同樣的也可以執(zhí)行級(jí)聯(lián)刪除, 當(dāng)A刪除了, B也跟著自動(dòng)刪除
注: 級(jí)聯(lián)操作并不會(huì)維護(hù)關(guān)系
此處注明: 千萬不要A設(shè)置了級(jí)聯(lián)刪除,然后B也設(shè)置了級(jí)聯(lián)刪除
當(dāng)刪除B對(duì)象的時(shí)候, 由于級(jí)聯(lián)刪除, B會(huì)select所有A, 然后刪除A, 但是A又觸發(fā)級(jí)聯(lián)刪除, A會(huì)select所有的B, 最終刪除所有的B, 以及所有的A, 就因?yàn)閯h除了一個(gè)B導(dǎo)致了如此嚴(yán)重的問題, 這個(gè)一定要避免!!!
在Order.hbm.xml中:
many-to-one標(biāo)簽中name屬性: 確定屬性名稱class屬性: 確定參照的類column屬性: 確定Order表參照Customer表的外建名往數(shù)據(jù)庫(kù)中保存Customer與Order:
Customer c = new Customer(); c.setName("tom"); Order o1 = new Order(); o1.setName("o1"); Order o2 = new Order(); o2.setName("o2"); //往c中添加Order信息, 維護(hù)關(guān)系 c.getOrderSet().add(o1);//Customer去維護(hù), 執(zhí)行update c.getOrderSet().add(o2);//執(zhí)行update //往Order對(duì)象中添加Customer, 維護(hù)關(guān)系 o1.setCustomer(c);//Order去維護(hù), 在insert中修改cid的值 o2.setCustomer(c); //保存到數(shù)據(jù)庫(kù) session.save(c); session.save(o1); session.save(o2);執(zhí)行上面的代碼, Hibernate執(zhí)行3次insert, 2次update, 需要注意的是在c, o1, o2 insert的過程中, 就已經(jīng)在維護(hù)關(guān)系(對(duì)Order表的cid外鍵進(jìn)行設(shè)置), 但是后面又對(duì)Order表執(zhí)行了2次update, 產(chǎn)生的問題就是重復(fù)
所以通過上面的代碼也可以看出, 當(dāng)維護(hù)關(guān)系的時(shí)候只需要維護(hù)一方, 另一方的關(guān)系就能得到維護(hù)
同理, 執(zhí)行delete操作: session.delete?; 執(zhí)行這條語句的時(shí)候, Hibernate會(huì)先將o1, o2的cid設(shè)置為null, 然后再對(duì)c進(jìn)行delete, 從Customer的角度維護(hù)關(guān)系, 但是Customer不去維護(hù)關(guān)系的時(shí)候, 就需要遍歷Customer的orderSet, 將所有的Order對(duì)象setCustomer(null)主動(dòng)切斷與Customer的關(guān)系, 設(shè)置所有Order的外鍵為null
總結(jié): 設(shè)置一對(duì)多關(guān)系下, 可以只讓一方維護(hù)關(guān)系, 另一方不維護(hù), 放棄維護(hù)關(guān)系的對(duì)象就是–非外鍵所在的對(duì)象, 就比如上面的操作, 讓Order 維護(hù)關(guān)系, Customer不去維護(hù)關(guān)系, 這種一方去維護(hù)關(guān)系也可以使用set標(biāo)簽中的inverse屬性, 使得關(guān)系的維護(hù)交給對(duì)方
未完待續(xù)~~
上面有錯(cuò), 還請(qǐng)指出, 如果認(rèn)為我寫的還不錯(cuò), 還請(qǐng)點(diǎn)個(gè)贊, 多多支持一下, O(∩_∩)O~~
總結(jié)
以上是生活随笔為你收集整理的Hibernate_2_Hibernate中对象状态及转化_一级缓存_Session详解_HQL/SQL/Criteria_一对多关系_级联操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python print 输出到txt_
- 下一篇: linux强制使用windows命名,如