Hibernate入門三
使用Hibernate最大的目的就是對數據庫進行crud操作。在講解之前,我們需要了解持久化以及持久化對象的三種狀態。
?
什麽是持久化
持久化就是把內存中的數據永久的存儲到數據庫中
?
什麽是持久化類
持久化類就是Java類與數據庫建立的一種映射關系,並把這個類稱做持久化類。實際上,就是一張數據表中的字段與類中的屬性字段相對象的類。
?
持久化類的編寫規範
1.需要提供無參數的構造方法
??因為Hibernate通過反射機制生成類的實例
2.需要私有屬性,並提供對應的get和set方法
??因為Hibernate底層會對獲取到的數據驚醒封裝
3.屬性盡量使用包裝類類型
?? 區分空和null4.類中必須存在一個唯一標識 OID與表中的主鍵對應
?? Hibernate利用這個這個唯一標識來區分內存中是否是同一個持久化類
5.不要使用final修飾類
??因為Hibernate有加載延遲機制,這個機制會產生代理對象。代理對象是通過字節 碼增強技術來完成的,其實就是通過產生子類的方式,如果使用final修飾持久化類,這個機制就會失敗。加載延遲機制是一種優化的手段。
?
Hibernate主鍵生成策略
主鍵的類型
- 自然主鍵
把具有業務含義的字段作為主鍵,稱為自然主鍵。比如,客戶的姓名(必須保證姓名不重復,唯一,非空),這類主鍵往往會因為業務的改變重新設計表,造成數據庫維護困難。- 代理主鍵
把具有非業務字段作為主鍵,稱為代理主鍵。通常是ID,類型是整數類型(比字符串節省空間)- Hibernate提供了幾個內置主鍵生成策略
1.increment:用於short int long類型。以自動增長的方式,每次增量是1。
2.identity:采用底層數據庫本身提供的主鍵生成標識,前提是數據庫支持自動增長的類型。
3.sequence:Hibernate根基底層序列生成標識符,前提是數據庫支持序列。
4.native:根據底層數據庫生成能力來判斷生成identity、sequence、hilo中的一種。適合跨數據庫開發。
5.uuid:采用128位uuid算法生成標識符
6.assigned:由Java程序負責生成標識符。如果不指定id的generator屬性,默認使用該屬性。適合自然類型。
?
Hibernate持久化對象的三種狀態
- 瞬時態
也稱為臨時態,托管態,實例是new出來的。不存在唯一標識OID,也沒有和Hibernate Session關聯 - 托管態
也稱為離線態,遊離態。當某個持久態狀態的實例與session失去關聯的時候就變成為托管態。但是,托管態對象仍然存在唯一 標識OID,與數據庫中的數據存在關聯,只不過托管態對象發生改變的時候,Hibernate無法檢測到。 - 持久態
對象存在OID,並且與Session關聯。值得註意的是,持久態對象在是事務還沒有提交之前變成持久態的。
下面通過列舉例子來說明上述內容
@Test
public void demo() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
// 瞬時態,此時沒有OID,也沒有與session關聯
User user = new User();
user.setUsername("robin");
Serializable save = session.save(user); // 持久態
transaction.commit();
session.close();
sessionFactory.close();
// 托管態,此時session關閉,沒有與session關聯,但是有OID
System.out.println(user);
}
轉換關系
?
瞬時態
1.瞬時態 -- 持久態
??調用save()或者saveOrUpdate()
2.瞬時態 -- 托管態
??為瞬時態添加 OID
?
持久態:可以從Session get() load()方法獲取,或者Query對象等
1.持久態 -- 瞬時態
??session.delete()刪除持久態化對象
2.持久態 -- 托管態
??session.evict()、clear()、close()方法。evict()用於清除一級緩存中的某一個對象,clear()用於清除一級緩存中的所有對象, close()關閉session,並且清除一級緩存。
?
托管態
1.托管套 -- 持久態
??執行update()、saveOrUpdate() lock()等
2,托管態 -- 瞬時態
??把對象的OID設置為null
?
持久態對象可以自動更新數據庫
依賴Hibernateu一級緩存
@Test
public void demo() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
User user = session.get(User.class, 2);
user.setUsername("Robin");
// session.update(user); 這句話可以省略,因為持久態的對象會自動更新數據庫
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
}
?
Hibernate一級緩存
緩存是計算機為了提高讀取速度而設計的。通常介於應用程序和永久性存儲介質之間。提高應用的運行能力,通常是內存。
?
Hibernate緩存分為一級緩存和二級緩存(redis替代),一級緩存是Hibernate內置緩存,不能刪除。
?
Hibernate一級緩存實際上就是session緩存。Session緩存是一個內存空間,存放相互管理的Java對象。在使用對象查找的時候,會使用OID在Hibernate一級緩存中進行查找,如果查找到了,就返回此對象,否則,就會去數據庫查找與之相同OID的對象。
?
只要session實例沒有結束生命周期,存放在它上面的緩存也不會消失。
一級緩存的特點
當應用程序調用Session的save()、update、saveOrUpdate()的時候,Session緩存中沒有相應的對象的時候,Hibernate會自動的從數據庫中提取對應的數據加載到一級緩存中
當應用程序調用Session load()、get(),以及Query中的、list()、iterator()的時候,Hibernate首先會從以及緩存中尋找對象,如果存在則不需要去數據庫中查找。,如果沒有則從數據庫中獲取並加載到一級緩存中
當調用Session.close()的時候,session緩存會被清空。
?
測試一級緩存
觀察控制臺輸出的SQL語句
@Test
public void demo() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
/**
* 查詢兩次
*/
/**
* 第一次執行你會查詢數據庫
* 第二次查詢只會去緩存中尋找
*/
User user = session.get(User.class, 1);
User user1 = session.get(User.class, 1);
transaction.commit();
session.close();
sessionFactory.close();
}
?
一級緩存內部結構
Hibernate向一級緩存中存儲數據的時候,會拷貝一份數據放在Hibernate快照區,當使用事務提交之後,會根據OID比較一級緩存中的數據和快照區中的數據是否一致,如果不一致,則執行更新操作,並且同步快照區的數據,否則則不執行任何操作。
?
Hibernate對事務的控制
?
- 什麽是事務?
通常對數據庫的操作過程中,一項事務會有一條或者多條SQL語句,只有當所有的語句正常執行的時候,所有的操作才會正常完成。如果中間出現異常現象,那麽所有的語句執行都不成功。換句話說,對於一組操作,要麽全部成功,要麽全部失敗。
? - 事務的四個基本特性
原子性 一致性 隔離行 持久性
原子性:對事務的操作,要不全部成功,要麽全部失敗。
一致性:事務完成的時候,必須使所有的數據保持一致。
隔離性:一個事務不能被另外一個事務幹擾。
持久性:一旦提交了事務,對數據庫進行了操作,所有的操作就不可逆。永久性的被改變。
? - 事務並發引發的問題
臟讀 不可重復讀 幻讀(虛讀)
臟讀:一個事務讀取到另一個未提交事務的數據
不可重復讀:一個事務中讀取到另外一個事務已提交的update數據,造成同一個事務中多次讀讀取數據不一致
幻讀:一個事務中讀取到另外一個事務已提交的insert數據,造成同一個事務中多次讀讀取數據不一致
? - 事務的隔離級別
讀未提交(read uncommitted 1級):允許讀取還未提交的數據,會造成臟讀,不可重復讀,幻讀
已提交讀(read committed 2級):允許在事務並發時,讀取已經提交的數據,可防止臟讀
可重復讀(repeatable read 4級):對相同字段的多次讀取結果是一樣的,可以防止臟讀,不可重復讀
幻讀(serializable 8級):提供嚴格的事務隔離,可防止臟讀,不可重復讀,幻讀
?
Hibernate事務管理
?
- 設置事務隔離級別(在核心配置文件中配置)
<property name="hibernate.connection.isolation">4</property> -
在業務層處理事務的方法
1.在業務層中獲取session,把它傳遞給持久層
2.使用ThreadLocal將業務層獲取到的session綁定到當前線程中去。然後到業務層獲取的時候獲取當前線程的session.<property name="hibernate.current_session_context_class">thread</property> sessionFactory.getCurrentSession() 可以不需要關閉session,線程結束之後會自動關閉 thread: Session對象的生命周期與本地線程綁定 jta:Session對象的生命周期與JTA事務綁定 managed:Hinernate委托程序來管理Session對象的生命周期
?
Hibernate其它的API
??
- Query
- Criteria
- SQLQuery
?Query是面對對象的Hibernate查詢操作。通過session.createQuery(),傳遞一個HQL語句,獲取Query對象。
@Test
public void demo() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
/**
* 創建Query
* 調用對象的方法
*/
Query query = session.createQuery("from User");
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
Criteria是一個完全面對對象,可擴展的條件查詢API,它不需要考慮數據庫底層的實現,以及SQL語句的編寫。它是Hibernate核心查詢對象,又稱為OBC(Object By Criteria)
@Test
public void demo() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
/**
* Criteria
* 創建Criteria對象
* 調用方法
*/
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
SQLQuery用來接收SQL語句,需要我們手動封裝數據
@Test
public void demo03() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
/**
* 對象
* 調用方法
*/
String sql = "select * from `tb_user`";
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list();
// List<Object[]> list = sqlQuery.list();
// for (Object[] user : list) {
// System.out.println(Arrays.toString(user));
// }
for (User user : list) {
System.out.println(user);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
Hibernate入門三