本文主要介紹Hibernate主鍵的生成策略、持久化類的編寫規則、 持久化對象的三種狀態、hibernate的緩存、Hibernate的事務。 ...
-
自然主鍵: 把有特定業務含義的欄位作為了主鍵 eg: 用戶的名字, 身份證號碼
-
代理主鍵: 把沒有特定業務含義的欄位作為了主鍵 eg: id
開發裡面的話通常用代理主鍵
2.主鍵的生成策略
Hibernate中為了更好的維護數據, 提供很多種主鍵生成策略.
2.2 主鍵策略類型
-
increment :自動增長,適用類型:short,int,long類型主鍵.在多進程和集群下不要使用.用的不是資料庫的自動增長, hibernate底層的增長策略,select max(id) from customer; 然後+1作為下一條記錄的ID.
-
assigned:需要用戶手動輸入OID的.
-
identity:自動增長,用的是資料庫的自動增長。適用類型:short,int,long類型主鍵.支持自動增長資料庫如Mysql
-
sequence:序列,適用類型:short,int,long類型主鍵.支持序列的資料庫如:Oracle.
-
native:本地策略,根據資料庫的底層採用使用identity還是sequence.
-
uuid:隨機的字元串,適用於字元串類型的主鍵.
規則: 如果主鍵類型是 int short long 用 native
如果主鍵類型是字元串, 用uuid
1.持久化類概述
在Hibernate中,用來描述資料庫表結構的類,稱之為持久化類.
Java類與資料庫的某個表建立了映射關係.這個類就稱為是持久化類
持久化類 = Java類 + hbm的配置文件
2.持久化類定義規範
-
遵循JavaBean定義規範
類是公有的
需要一個無參的構造函數
屬性是私有的,需要提供公共的getter和setter方法進行訪問屬性
-
必須用一個屬性描述資料庫表的主鍵
-
主鍵屬性的類型必須是引用類型,且需要實現Serializable介面
1.概述
由持久化類創建的對象就是持久化對象。Hibernate為了管理持久化對象:將持久化對象分成了三個狀態.hibernate底層實現過程中,定義的三種狀態主要方便開發人員調用session的API.
區分三種狀態:
瞬時態 :沒有持久化標識OID的,沒有納入到session的管理.
持久態 :有持久化標識OID的,已經納入到session的管理.
托管(游離態)態:有持久化標識OID的,沒有納入到session的管理.
java代碼:
/** * 區分三種狀態: * 瞬時態: 沒有持久化標識oid,沒有納入Session管理 * 持久態: 有持久化標識oid,並且納入了Session管理 * 托管態: 有持久化標識oid,但沒有納入Session管理 */ @Test public void fun01(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); transaction.begin(); User user = new User();//瞬時態 user.setUname("張三"); user.setUage(18); session.save(user); System.out.println(user.toString());//持久態 transaction.commit(); session.close(); System.out.println(user.toString());//托管態 }
沒有持久化標識OID, 沒有被納入到Session對象的管理
-
獲得:new對象
-
狀態轉換:
瞬時態--->持久態:save()/saveOrUpdate();
瞬時態--->托管態:把瞬時態對象設置一個id
2.2持久態對象
有持久化標識OID,已經被納入到Session對象的管理
-
獲得:get()/load()/find()..
-
狀態轉換:
持久態--->瞬時態:session.delete(); (Hibernate中不建議使用的)
持久態--->托管態:close()/clear()/evict(Object obj);
2.3托管態對象
有持久化標識OID,沒有被納入到Session對象的管理
-
獲得:new對象,給對象設置id
-
狀態轉換:
托管態-->瞬時態:把對象的id設置為null
托管態--->持久態:update()/saveOrUpdate();
持久態對象依賴於緩存可以自動更新資料庫
-
Java代碼
1 @Test 2 public void fun05(){ 3 Session session = HibernateUtils.openSession(); 4 Transaction transaction = session.beginTransaction(); 5 transaction.begin(); 6 //持久態對象 7 User user = session.get(User.class, 1); 8 user.setUname("李四"); 9 //session.update(user);可以不寫,因為當前的user是持久化對象 10 11 transaction.commit(); 12 session.close(); 13 }
1.緩存概述
緩存就是一塊記憶體空間。
將數據源(資料庫或者文件)中的數據讀取出來存放到緩存中,再次獲取的時候 ,直接從緩存中獲取,這樣可以提升程式的性能!
作用:提升程式的性能
2.Hibernate的緩存類別
一級緩存:session對象的緩存,自帶的不可卸載的. 一級緩存的生命周期與session一致。
二級緩存:二級緩存可以在多個session中共用數據。一般不會用,企業里通常使用Redis
3.一級緩存
在 Session 介面的實現中包含一系列的 Java集合,這些 Java 集合構成了 Session 緩存. 只要 Session 實例沒有結束生命周期, 存放在它緩存中的對象也不會結束生命周期.
當session的save()方法持久化一個對象時,該對象被載入緩存,以後即使程式中不再引用該對象,只要緩存不清空,該對象仍然處於生命周期中。當試圖get()、 load()對象時,會判斷緩存中是否存在該對象,有則返回,此時不查詢資料庫。沒有再查詢資料庫.
@org.junit.Test public void fun03(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); //持久態對象 User user1 = session.get(User.class, 1);//馬上發送一條sql語句 System.out.println(user1.toString()); User user2 = session.get(User.class, 1);//馬上發送一條sql語句 System.out.println(user1 == user2);//true transaction.commit(); session.close(); }
測試結果:
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.uname as uname2_0_0_,
user0_.uage as uage3_0_0_
from
user user0_
where
user0_.uid=?
User{uid=1, uname='李四', uage=18}
true
4.一級緩存的內部結構:(緩存區, 快照區)
事務就是邏輯上的一組操作,組成事務的各個執行單元,操作要麼全都成功,要麼全都失敗.
2.事務的特性
原子性: 事務不可分割.
eg: 張三 1000 李四 1000; 張三給李四轉100, 要麼轉賬成功,要麼失敗
一致性: 事務執行的前後數據的完整性保持一致.
eg: 張三 1000 李四 1000 =2000; 張三給李四轉100, 成功了 張三 900 李四1100 = 2000; 失敗
隔離性: 一個事務執行的過程中,不應該受到其他的事務的干擾.
持久性: 事務一旦提交,數據就永久保持到資料庫中.
eg: 張三 1000 李四 1000, 給李四轉520;
3.不考慮隔離性會出現的相關問題
-
臟讀: 一個事務讀到了另一個事務未提交的數據.
-
不可重覆讀: 一個事務讀到了另一個事務已經提交的update數據,導致多次查詢結果不一致. 張三 1000 ; 李四 1000
-
虛讀: 一個事務讀到了另一個事務已經提交的insert數據,導致多次查詢結構不一致.
4.隔離級別
隔離級別 | 含義 |
---|---|
READ_UNCOMMITTED | 允許你讀取還未提交的改變了的數據。可能導致臟、幻、不可重覆讀 |
READ_COMMITTED | 允許在併發事務已經提交後讀取。可防止臟讀,但幻讀和 不可重覆讀仍可發生 |
REPEATABLE_READ | 對相同欄位的多次讀取是一致的,除非數據被事務本身改變。可防止臟、不可重覆讀,但幻讀仍可能發生。 |
SERIALIZABLE | 完全服從ACID的隔離級別,確保不發生臟、幻、不可重覆讀。這在所有的隔離級別中是最慢的,它是典型的通過完全鎖定在事務中涉及的數據表來完成的。 |
實際開發中,不會選擇最高或者最低隔離級別,選擇 READ_COMMITTED(oracle 預設)、REPEATABLE_READ (mysql預設)
5.Hibernate配置隔離級別
hibernate通過在hibernate.cfg.xml的配置文件中設置隔離級別:
<property name="hibernate.connection.isolation">4</property>
取值
1: Read uncommitted isolation,讀未提交
2: Read committed isolation,讀已提交,解決臟讀。
4: Repeatable read isolation,可重覆讀
8: Serializable isolation,串列化
6.hibernate對 session的管理
6.1把Session綁定在當前線程
在開發中,通常在業務層進行事物管理,在Dao層操作資料庫. 也就是說業務層需要連接(Session)開啟事物,Dao層需要連接(Session)操作資料庫,如何保證這些連接是同一個呢?
在JDBC階段,我們通過了兩種方式解決:
1.向下傳遞參數
2.綁定到TreadLocal裡面.
在Hibernate中,Session 對象與本地線程綁定很簡單,只需要兩步:
-
在hibernate.cfg.xml文件中,添加屬性,開啟與本地線程綁定的session
<property name="hibernate.current_session_context_class">thread</property>
-
通過SessionFactory的getCurrentSession()方法獲得Session
Session session = sessionFactory.getCurrentSession();
註意:通過getCurrentSession()方法獲得的session,無需調用close方法釋放資源。當事物提交或者回滾,會自動釋放資源.
6.2 Session獲取方式的區別
-
調用getCurrentSession()方法時,會判斷當前線程中是否綁定了session。
如果綁定了,直接返回線程中綁定的session
如果沒有綁定,先去創建一個session,然後講session存儲到當前線程中,再返回。
-
調用openSession()方法時,只會創建一個新的session,且不會存儲到當前線程。
-
通過getCurrentSession()方法獲得的session,無需調用close方法釋放資源. 通過openSession()方法獲得的session需要手動釋放資源。