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