Hibernate知識點復習之二
阿新 • • 發佈:2018-10-15
不存在 策略 十六 關閉 ner incr 整數 歸納 隔離 Hibernate學習之二
一 Hibernate持久化類
1 什麽是持久化類? Hibernate是持久層ORM映射框架, 專註於數據的持久化 ,所謂的持久化 就是將內存中的數據永久存儲到關系型數據庫的過程。 而持久化類就是 通過映射文件與數據庫建立起映射關系的Java類。 2 持久化類的編寫規則: 1. 需提供無參構造方法。(Hibernate底層是通過反射技術生成持久類的實例) 2. 類屬性需私有化, 提供私有的getter和setter方法。(Hibernate底層將查詢到數據通過get/set方法進行封裝處理) 3.類屬性類型使用包裝類。(包裝類的語義描述更清晰,如:Integer中 null 和 0 代表兩種情況,而這兩種情況 int 只能使用 0 來表示) 4.持久化類要有一個唯一標識(oid)與表主鍵對應。(Hibernate需通過此唯一標識oid來區分內存中是否是同一個持久化對象,Hibernate不允許存在同oid的兩個持久化對象) 5.持久化類盡量不使用final修飾。(Hibernate的延遲加載機制 是通過字節碼增強技術來產生一個代理對象,通過產生當前類的一個子類對象實現, 若final修飾,不能產生子類,也就不能產生代理對象, Hibernate的延遲加載策略(一種優化手段)就會失效。 3 Hibernate的主鍵生成策略 1.主鍵類型 #自然主鍵:把具業務含義的字段作為主鍵,如customer表中的 name作主鍵 #代理主鍵:把不具業務含義的字段作為主鍵,該字段一般取名為id,通常為整數類型(比字符串類型節省更多空間) 2.主鍵生成策略 <generator class="主鍵生成策略屬性"></generator> #assigned:自然主鍵策略,需開發人員手動錄入指定主鍵,若id不指定generator屬性,Hibernate默認使用這種主鍵生成策略。 #increment:代理主鍵策略,整型數據主鍵自增,增量為1,存在線程安全問題,不適用多線程操作同一張表的情況,不能在集群環境下使用 #uuid:代理主鍵策略,產生隨機字符串作為主鍵,主鍵類型必須為String ,Hibernate采用128位的UUID算法來生成(長度為32位十六進制的)唯一的字符串標識符 #identity:代理主鍵策略,采用底層數據庫本身提供的主鍵生成標識符,該生成器要求數據庫中把主鍵定義為自增長類型 #sequence:代理主鍵策略,根據底層數據庫序列生成標識符,該數據庫需支持序列(Oracle的主鍵生成策略) #native:代理主鍵策略,根據底層數據庫 自動生成標識符能力來選中 identity,sequence,hilo(高低算法生成器) 三種生成器中的一種,適合跨數據庫平臺開發 4 Hibernate的持久化對象的三種狀態 1 概述:Hibernate為了更好管理持久化類,特將持久化類分三種狀態:瞬時態,持久態,托管態 2 瞬時態(transient):不存在持久化標識oid,尚未與Hibernate的Session關聯的持久化對象。 細述:瞬時態也稱臨時態或自由態,瞬時態的實例由new 命令創建,在內存開辟空間的孤立對象,與數據庫無關聯。 3 持久態(persistent):存在持久化標識oid,加入到Session緩存中,且相關聯的Session沒有關閉(執行close()方法),持久化狀態對象的任何變化都會自動同步到數據庫中 如:存在持久態對象c,執行方法c.setCust_name("微軟公司")後 不需調用Session.update(c) 即可自動把數據更新到數據庫中 細述:值得一提的是,持久化對象是在事務提交前變成持久態的。Session.save()方法就是 瞬時態 轉換為 持久態的 過程 4. 托管態(detached):失去Session關聯,仍然存在oid,與數據庫存在關聯 細述:托管態也稱遊離態或離線態,當某個持久化狀態的對象與Session關聯被關閉了就會變成托管態,托管態對象發生改變時Hibernate不能檢測到 Session.close()方法就是 持久態 轉換為 托管態的過程 5. 三種狀態相互轉換 #瞬時態 *轉 持久態:save()或saveOupdate *轉 托管態:為瞬時態對象設置oid #持久態 *轉 瞬時態:delete() *轉 托管態:close() #托管態 *轉 瞬時態:將對象的oid設為null *轉 持久態:update()或 saveOrUpdate()
二 Hibernate的一級緩存
@概述:持久化對象可以自動更新數據庫依賴於Hibernate的一級緩存 @什麽是Hibernate的一級緩存? #緩存概念:緩存介於應用程序和永久性數據存儲源(硬盤,數據庫)之間,其作用是降低應用程序直接讀取永久性數據存儲源的頻率,從而提高應用的運行性能 緩存中的數據是永久性數據存儲源中數據的拷貝,它的物理介質通常是內存 #Hibernate緩存:Hibernate緩存分為一級緩存和二級緩存,Hibernate這兩級緩存都位於持久層,存儲的都是數據庫備份數據, 其中Hibernate一級緩存為內置緩存,不能被卸載 #Hibernate一級緩存: *概念:Hibernate的一級緩存就是指Session緩存(一塊內存空間),用來存放相互管理的java對象。Session接口的實現包含了一系列的Java集合,這些java集合 構成了Session緩存,只要Session實例沒有結束生命周期,存放在它緩存中的對象就不會結束生命周期,因此一級緩存也被稱為是Session基本的緩存 *持久化對象自動更新數據庫的原理: 在使用Hibernate查詢對象時,會先使用對象的oid屬性在Hibernate的一級緩存中(Session緩存)進行查找,如果找到匹配oid值的對象, 則直接從一級緩存中取出,不會再查詢數據庫。若沒有找到匹配oid值的對象,則去數據庫中查找相應的數據,從數據庫中查詢到的數據也會 放進一級緩存中。 *Hibernate的一級緩存作用:減少對數據庫訪問的次數 *Hibernate一級緩存的特點: &當應用程序調用Session接口的save(),update(),saveOrUpdate(),如果Session緩存中沒有相應的對象,Hibernate就會自動進入數據庫查詢, 將查詢到相應的對象信息加入到一級緩存中 &當調用Session接口的load(),get()方法,以及Query接口的 list(),iterator() 方法時,先判斷Session緩存中有無對象,有則返回,沒有則 數據庫查詢,並將查詢結果存進Session緩存中。 &當調用Session的close()方法,Session緩存會被清空。 *Hibernate一級緩存是否存在示例: //第一次獲取id為1的Customer對象,Session緩存中沒有,會進行數據庫查詢操作,打印出sql查詢語句,並存進Session緩存中 Customer c1 = session.get(Customer.class,1L); System.out.println(c1); System.out.println("---------------------------------------"); //第二次獲取同一個id為1的Customer對象,此時其已存在Session緩存中,不會進行數據庫查詢操作,不會打印出sql查詢語句 Customer c2=session.get(Customer.class,1L); System.out.println(c2); System.out.println(c1==c2); //返回true,獲取的是同一個對象 *Hibernate一級緩存的快照: &概述:一級緩存之所以可以更新數據庫,依賴於一級緩存中的快照區域 &底層原理:Hibernate向一級緩存存數據時,同時會拷貝一份到一級緩存中的快照區裏。當執行事務提交commit()方法時,Hibernate會 比對一級緩存中的數據和內部的快照區數據是否一致,若不一致則底層自動update操作,把新數據同步更新到數據庫中, 若一致則不更新。 &作用:確保一級緩存中 的數據與數據庫的一致 *Hibernate一級緩存和一級緩存中的快照區職能總結: &一級緩存主要應用於 Session進行CRUD中查取操作時,減少對數據庫的訪問 (查取操作) &快照區則為了保證 一級緩存區的數據與數據庫一致,而對數據庫進行數據更新 (更新操作)
三 Hibernate的事務控制
1. 什麽是事務? #概述:在數據庫操作中,一項事務是由一條或多條操作數據庫的sql語句組成的不可分割的工作單元。當事務中所有sql操作都正常時,整個事務才可被提交到數據庫中, 若有一項操作沒有完成,則整個事務會被回滾。 #歸納理解:事務可以理解為邏輯上的一組操作,組成這組操作的各個單元,要麽一起成功,要麽一起失敗 #事務的ACID特性: &原子性(Atomic):將事務中所有操作捆綁成一個不可分割的單元,不可分割在於,事務的所有操作要麽全部執行要麽全部不執行 &一致性(Consistency):事務完成後,所有數據都保持一致狀態 &隔離性(Isolation):一個事務的執行不能被其他事務幹擾。即一個事務的操作及使用的數據對並發的其他事務是隔離的,並發執行的各個事務之間不能互相幹擾。 &持久性(Durablility):也稱永久性,指一個事務一旦提交,它對數據庫中數據的改變是永久性的,完成提交後,產生的其他操作或故障不會對其影響。 2. 事務中的並發問題: #概述:實際開發中,數據庫是要被多個用戶訪問的。多個事務訪問同一個數據庫時會發生並發問題。 #事務並發產生的問題: & 臟讀(Dirty Read):一個事務讀取到另一個事務中未提交的數據 如:事務T1修改了一行數據,但是還沒有提交,這時候事務T2讀取了被事務T1修改後的數據, 之後事務T1因為某種原因Rollback了,那麽事務T2讀取的數據就是臟的 & 不可重復讀(None-Repeatable Read):一個事務中兩次讀同一行數據,可兩次讀到的數據內容不一致 如:事務T1讀取某一數據,事務T2讀取並修改(update)了該數據,T1為了對讀取值進行檢驗而再次讀取該數據,便得到了不同的結果。 & 虛讀/幻讀:事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺少了第一次查詢中出現的數據 如:事務T1在查詢某數據庫的數據時,T2在該數據庫插入(insert)或刪除(delete)了一條記錄,事務T1查完第一次,想確認查詢第二遍時發現前後數據數量不一致。 & 更新丟失(Update Lost):兩個事務都同時更新(update)一行數據,但是第二個事務卻中途失敗退出,導致對數據的兩個修改都失效了。 這是因為系統沒有執行任何的鎖操作,因此並發事務並沒有被隔離開來。 #為解決事務並發問題而定義的4個事務隔離級別: &讀未提交(Read Uncommitted,1級): 一個事務可以訪問另一個事務未成功提交的修改(update)和插入(insert)數據,但當一個事務在寫數據時,另一個事務不可也進行寫操作,只允許讀此行數據。 讀事務不阻塞其他讀事務和寫事務,未提交的寫事務阻塞其他寫事務但不阻塞讀事務。 此隔離級別可以防止更新丟失,但不能防止臟讀、不可重復讀、幻讀。 & 讀已提交(Read Committed,2級,oracle默認的): 一個事務可以訪問另一個事務成功提交的修改(update)和插入(insert)數據,但未提交的寫事務,禁止其他事務訪問該行。 讀事務允許其他讀事務和寫事務,未提交的正在進行的寫事務禁止其他讀事務和寫事務 此隔離級別可以防止更新丟失、臟讀,但不能防止不可重復讀、幻讀。 & 可重復讀(Repeatable Read,4級,mysql默認的): 以操作同一行數據為前提,讀事務禁止其他寫事務但不阻塞讀事務,未提交的寫事務禁止其他讀事務和寫事務。 此隔離級別可以防止更新丟失、臟讀、不可重復讀,但不能防止幻讀 & 序列化/串行化(Serializable,8級): 提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接著一個地執行,不能並發執行。(相當於鎖表,性能差沒人用) 此隔離級別可以防止更新丟失、臟讀、不可重復讀、幻讀。 & 總結:隔離級別越高,越能保證數據的完整性和一致性,但是對並發性能的影響也越大。對於多數應用程序, 可以優先考慮把數據庫系統的隔離級別設為Read Committed。它能夠避免更新丟失、臟讀,而且具有較好的並發性能。 盡管它會導致不可重復讀、幻讀這些並發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。 & 配置文件對事務中隔離級別進行配置: 隔離級別為: 0001 1 第一級別(讀未提交) 0010 2 第二級別(讀已提交) 0100 4 第三級別(讀可重復)(mysql數據庫為4) 1000 8 第四級別(串行化) <property name="hibernate.connection.isolation">4</property>
四 Hibernate的事務管理
1. 如何保證在Service層開啟事務時使用的Session對象,與在dao層進行多個操作時使用的是同一個Session對象?
# 在業務層獲取到Session後,將Session作為參數傳遞給DAO
# 使用ThreadLocal將業務層獲取到Session綁定到當前線程中,從而,dao層獲取的Session都是從當前線程。具體實現Hibernate幫助我們完成,只需進行配置
& Hibernate提供三種管理Session對象的方法:
1 Session對象的生命周期與本地線程綁定(這是調用sessionFactory.getCurrentSession()方法,獲取與當前線程綁定Session必備的配置)
<property name="hibernate.current_session_context_class">thread</property>
2 Session對象的生命周期與JTA事務綁定
<property name="hibernate.current_session_context_class">jta</property>
3 Hibernate委托程序來管理Session對象的生命周期
<property name="hibernate.current_session_context_class">managed</property>
五 Hibernate的Query對象
1 Query對象(代表面向對象的一個Hibernate查詢操作)
概述:在Hibernate中,通常使用session.createQuery()方法接收一個hql語句,獲取一個Query對象,然後調用Query對象的list()或uniqueResult()方法進行查詢,
hql(Hibernate Query Language)語句,語法很像sql,但它是全面向對象的,如果HQL語句含有參數,則可調用Query的setXxx()設置參數
2 Query對象的常用API查詢示例:
# 基本查詢:
String hql="from Customer"; //書寫hql語句
Query query = session.createQuery(hql); //創建查詢對象
List<Customer> list = query.list(); //執行查詢
#條件查詢:
String hql="from Customer where cust_id = 1L"; //書寫hql語句
Query query = session.createQuery(hql); //創建查詢對象
Customer uniqueResult = (Customer) query.uniqueResult();//執行查詢
#占位符?的使用
String hql="from Customer where cust_id = ?"; //書寫hql語句
Query query = session.createQuery(hql); //創建查詢對象
//query.setLong(0, 1L);
query.setParameter(0,1L);//此方法會自動幫你轉化處於占位符中的數據類型
Customer uniqueResult = (Customer) query.uniqueResult();//執行查詢
#命名占位符 =: 的使用
String hql="from Customer where cust_id=:myId"; //書寫hql語句--設置命名占位符
Query query = session.createQuery(hql); //創建Query對象
query.setParameter("myId",1L); //為命名占位符設置參數
Customer uniqueResult = (Customer) query.uniqueResult(); //執行查詢
# 分頁查詢:
String hql="from Customer";
Query query = session.createQuery(hql);
//limit 0,5
query.setFirstResult(0); //從0條記錄開始查詢
query.setMaxResults(5); //查詢到第5條
List<Customer> list = query.list();
3 Query的其他API
# setter方法(如:setParameter("","");setLong("",""))
提供一系列的setter方法針對不同數據類型設置 查詢參數
#iterator()
該方法用於查詢語句,叠代讀取時按照順序讀取,把使用到數據轉換到java對象
# executeUpdate()
Hbernate3 新特性,它支持hql的更新和刪除操作
六 Hibernate的Criteria對象
1 概述:
Criteria是一個完全不需考慮數據庫底層實現,sql的編寫,完全面向對象,可擴展的條件查詢API.它是Hibernate框架的核心查詢對象。
Criteria查詢 也稱QBC(Query By Criteria )查詢,它是Hibernate的一種對象檢索方式。
2 org.hibernate.criterion接口:
Criterion是Hibernate一個提供面向對象查詢條件的 接口,Cirterion接口的一個實例就是一個單獨的查詢條件,而Criterion實例是由工廠類Restrictions的靜態方法完成。
Criteria對象需通過add()方法添加Criterion實例查詢條件,從而創建查詢。
3 Criteria條件查詢sql操作符對應的方法:
* > gt()
* >= ge()
* < lt()
* <= le()
* == eq()
* != ne()
* in in()
* between and between()
* like like()
* is not null isNotNull()
* is null isNull()
* or or()
* and and()
4 Criteria的QBC查詢API:
#基本查詢
//創建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//執行QBC查詢
List<Customer> list = criteria.list();
#條件查詢
//創建查詢
Criteria criteria = session.createCriteria(Customer.class);
//設置查詢條件
criteria.add(Restrictions.eq("cust_id",1L));
//執行查詢
Customer c = (Customer) criteria.uniqueResult();
#分頁查詢
//創建查詢對象
Criteria criteria = s.createCriteria(Customer.class);
//設置查詢條件
criteria.setFirstResult(0);
criteria.setMaxResults(5);
//執行查詢
List<Customer> list = criteria.list();
#查詢總記錄
//創建查詢對象
Criteria criteria = s.createCriteria(Customer.class);
//設置查詢條件
criteria.setProjection(Projections.rowCount());
//執行查詢
Long uniqueResult = (Long) criteria.uniqueResult();
七 Hibernate的SQLCriteria對象
1 概述:SQLCriteria接口用於接收sql原生語句進行查詢,然後調用list()或 uniqueResult()方法獲取結果
但sql語句不會手動封裝到實體,需要我們手動調用 addEnity()進行封裝
2 SQLCirteria查詢示例:
//書寫原生sql語句
String sql="select * from cst_customer";
//創建查詢對象
SQLQuery sqlQuery = s.createSQLQuery(sql);
//3 獲取查詢結果
//沒使用手動封裝實體的方式:
/*List<Object[]> list = sqlQuery.list();
for(Object[]objs:list) {
System.out.println(Arrays.toString(objs));
}*/
//使用手動封裝實體方式:
sqlQuery.addEntity(Customer.class);
//執行查詢
List<Customer> list = sqlQuery.list();
八 Hibernate的Query,Criteria,SQlCriteria三大API對象總結:
Query對象:書寫的是hql語句,然後放進 session.createQuery(hql)方法創建查詢對象,由setter方法設置查詢條件,list()和uniqueResult()執行查詢獲取結果
Criteria對象:不需書寫hql語句,使用 session.createCriteria(xxx.class)關聯對應實體,由QBC查詢方法設置查詢條件,list()和uniqueResult()執行查詢獲取結果
SQLQuery對象:書寫的是原生sql語句,使用 session.createSQLQuery(sql)創建查詢對象,addEnity(xxx.class)封裝實體,list()和uniqueResult()執行查詢獲取結果
Hibernate知識點復習之二