一 概述 1.JPA Java Persistence API,是Java EE為ORM框架定義的規範,任何使用java語言的ORM框架都必須實現該規範。Hibernate/Mybatis都是是JPA的一種實現。 2.ORM Object Relational Mapping,對象到關係的映射,在關 ...
一 概述
1.JPA
Java Persistence API,是Java EE為ORM框架定義的規範,任何使用java語言的ORM框架都必須實現該規範。Hibernate/Mybatis都是是JPA的一種實現。
2.ORM
Object Relational Mapping,對象到關係的映射,在關係型資料庫與對象之間建立映射關係,以實體對象操作關係型資料庫。
3.持久化
將對資料庫的操作永久地反映到資料庫中的過程叫做持久化。
4.持久層框架
封裝了對資料庫進行持久化操作的框架叫做持久化框架。所謂框架就是在內部實現了一些常用的基本操作,提供簡單的介面,縮減操作步驟,而且擴展了功能。
二 資料庫連接池
1.背景
資料庫連接是一個極其有限的寶貴資源,在Web應用程式中表現得尤為突出。Web應用訪問量大,而資料庫支持的併發連接數目是有限的,連接越多,速度越慢,降低了用戶體驗。
在資料庫連接池產生以前,訪問資料庫需要先建立連接,訪問結束後關閉連接,下次需要時再重覆創建與關閉過程,而資料庫連接的創建與關閉本身消耗大量的系統資源,這時產生了共用資料庫連接的思想,資料庫連接池應運而生。
2.資料庫連接池的含義
- 資料庫連接池提供與管理用於訪問資料庫的連接。
- 資料庫連接池在初始化階段會創建一定數量的資料庫連接,投放到數據連接池中。
- 用戶訪問資料庫時不創建連接,而是從資料庫連接池中獲取連接,訪問完畢後,不關閉連接,而是將連接歸還連接池,以實現連接的重覆使用。
3.常用數據連接池
- C3P0是一種開放源代碼的JDBC連接池。
- DBCP。
4.配置數據源
Hibernate框架推薦使用C3P0:
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
三 Hibernate簡介
1.基本流程
2.Configuration
負責載入配置文件,啟動Hibernate。配置文件的預設名稱為“hibernate.cfg.xml”,放在類路徑下。
3.SessionFactory
負責創建Session對象,保存了當前資料庫中所有的映射關係,線程安全。重量級對象,初始化過程耗費大量的資源,因此在應用程式中應避免創建多個SessionFactory對象。
4.Session
⑴含義
代表應用程式與資料庫的一次會話,是Hibernate中持久化操作的核心,直接負責所有的持久化操作。
⑵非線程安全
session對象線程不安全,應避免多個線程共用一個Session對象。多個線程共用一個session對象,可能會因為session緩存的存在出現數據泄露,或者一個線程關閉了session對象,另一個線程出現異常。
⑶依賴事務
Session只能在事務內部運行,即未開啟事務,無法運行Session。
⑷創建
Session session=sessionFactory.openSession();
Session session=sessionFactory.getCurrentSession();
- 第一種方式不需要配置,直接使用,第二種方式必須在配置文件中配置,配置如下:
<property name="current_session_context_class">thread</property>
- openSession每調用一次創建一個Session對象,getCurrentSession在同一個線程內部獲得的是同一個Session對象。
- 第二種方式創建的對象與線程綁定,第一種未與線程綁定。第二種方式創建的對象在事務提交或者回滾後自動關閉,第一種方式創建的連接必須手動關閉。
⑸關閉
- Session一旦被關閉,就與線程解除了綁定關係,下一次通過該線程獲得的是不同的Session對象。
- Session關閉以後,斷開了與資料庫的連接,就無法通過該Session對象訪問資料庫。
Session一旦關閉,就標志著應用程式與資料庫的一次會話結束,再次通信需要建立新的會話。
5.主鍵生成策略
生成策略 | 含義 | 維護方 |
increment | 獲取資料庫中當前主鍵的最大值,加1作為新數據的主鍵 | Hibernate |
identity | 按照自增方式生成主鍵 | 資料庫 |
native | 從底層資料庫支持的主鍵生成策略中選擇 | 資料庫 |
assigned | 由程式員手動生成主鍵 | 程式員 |
sequence | 基於sequence表生成主鍵 | 資料庫 |
uuid | 生成一個全球唯一的32位主鍵 | 資料庫 |
foreign | 根據另一張表的主鍵生成主鍵,形成一對一主鍵關聯 | Hibernate |
四 持久化對象的狀態
1.瞬時狀態
對象被創建、未被Session調用時的狀態,與資料庫中的數據無連接,一旦被Session通過save或者saveOrUpdate調用方法轉化為持久化狀態。
2.持久化狀態
被Session調用後、與資料庫中的數據存在關聯的狀態。
3.脫管狀態
當Session對象關閉以後,持久化對象由持久狀態轉化為脫管狀態,持久化對象處在脫管狀態下仍然與資料庫中的數據存在關聯,通過update或者saveOrUpdate轉化為持久化狀態
4.集合角度
假如把關係型資料庫中的表看做一個持久化類,每一行記錄都是一個該類的對象,即持久化對象,一個對象如果在集合之外,則處於瞬時狀態;在集合之內並且正在被Session調用,處在持久化狀態;如果Session關閉,處在脫管狀態。
5.記憶體地址
對象的狀態發生改變時,對象在記憶體中的地址並未發生改變,仍然是同一對象,只是對象與資料庫的關係發生改變。
五 持久化操作
1.一般步驟
2.插入數據
session.save(Object obj);
3.查詢數據
⑴get
Object obj=(Object)session.get(Object.class,Serializable id);
⑵load
Object obj=(Object)session.get(Object.class,Serializable id);
返回對象的代理,在對象被調用時,才向資料庫發送SQL語句。
4.刪除數據
Object obj=session.get(Object.class,Serializable id); session.delete(obj);
5.修改數據
Object obj=session.get(Object.class,Serializable id); obj.setter();//調用setter方法修改對象屬性
6.其他方法
- clear():清空Session緩存,取消所有未執行的操作。
- evict():立即將Session緩存中對象的引用變數賦值為null,不會生成SQL語句。
7.操作的本質
假定session緩存中保存的是對象本身,而不是對象的引用,那麼清空session緩存,會銷毀對象,測試一下:
@Test
public void testClear() {
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
Student stu = session.get(Student.class, 1);
System.out.println("stu=" + stu);
session.clear();
System.out.println("stu=" + stu);
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
輸出:
很明顯,session緩存清空以後,依然可以輸出對象的詳情,說明對象依然存在,從而得出結論:session緩存中保存的不是對象,而是對象的引用。
載入完成以後,在session緩存中建立一個對象的引用變數,並且使引用變數stu也指定該對象。
- get()/load()/save(stu):在session緩存中建立引用變數stu,指向記憶體中的對象obj。
- delete(stu):不是從記憶體中刪除對象obj,而是使session緩存中的引用變數“stu0=null”。
- update(stu):對資料庫的修改直接來源於session緩存,所以在執行修改操作前必須保存session緩存中存在該對象,即session緩存中存在對象的引用。
六 同步時間點與刷新時間點
1.同步時間點
事務提交是Hibernate中唯一的同步時間點,事務提交時將Session緩存中的數據同步到資料庫。
2.刷新時間點
遇到Query查詢、flush方法、事務提交時,執行刪除與修改操作更新session緩存中的內容,只有在事務提交時才同步到資料庫。
3.本質
同步時間點與刷新時間點所做的工作就是將以面向對象形式對數據的操作轉化為以SQL形式對資料庫的操作,因為無論框架怎麼封裝,底層資料庫所能識別與執行的命令只有SQL語句,框架提供了面向對象這種相對簡單的操作資料庫的方式,底層再將這種方式轉化為資料庫接受的方式。
刷新時間點與同步時間點就是啟動轉化的時機。刷新時間點將轉化的SQL語句寫入session緩存,同步時間點將轉化的SQL語句寫入資料庫。
4.flush
修改緩存中已有的對象,比如修改對象屬性值,刪除對象,不會清空緩存,不會同步到資料庫,不影響那些與緩存內容無關的操縱,比如save\get操作不受flush影響,立即執行。
5.快照約束
同步時間點與刷新時間點都受快照的約束。
七 緩存
1.Hibernate緩存結構
將從資料庫中載入的對象分別保存在記憶體的3個區域,各區域之間相互獨立,互不影響。
2.一級緩存與二級緩存內容結構
一級緩存與二級緩存中的內容都以Map集合的形式存儲,key是持久化類與唯一性標識(id)的組合,value是對象的引用變數。
判斷一級緩存或者二級緩存中是否存在一個對象的依據是,該對象的持久化類與唯一性標識構成的組合是否存在於Map集合中。
3.一級緩存
⑴生命周期
一級緩存是Session級的,生命周期與Session相同,隨Session的創建而創建,隨Session的銷毀而銷毀。
⑵內部共用
Session緩存中的數據在Session內部共用,Session之間不共用。
4.快照
⑴作用
快照記憶體中一塊存儲區域,提供了一種修改審查機制。
⑵基本原理
事務提交時,將緩存中準備同步到資料庫中的內容與快照中的內容進行對比,不一致才同步到資料庫,避免了對資料庫不必要的訪問,減輕了資料庫的負擔。
5.二級緩存
⑴作用範圍
二級緩存即SessionFactory緩存,為所有Session對象共用。
⑵配置
Hibernate本身並未實現二級緩衝,需要使用第三方插件,其中一種插件為EHCache,註冊後才可使用
- 開啟二級緩存:
-
<property name="hibernate.cache.use_second_level_cache">true</property>
- 二級緩存對應記憶體一塊區域,需要指明該區域的管理者,即二級緩存提供商:
-
<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
- 在src目錄下加入緩衝配置文件:ehcache.xml。
實體類只有在二級緩存中設定了使用策略之後才可以緩存在二級緩存中,設定使用策略有兩種方式:
- 在映射文件中配置:
-
<class> <cache usage="read-only"/> </class>
- 在配置文件中配置:
-
<class-cache class=""usage=""/>
6.Query緩存
⑴什麼是Query緩存?
用來存儲Query查詢結果的記憶體區域,獨立於一級與二級緩存,供Query查詢使用。
⑵開啟
Hibernate預設關閉了Query緩存,如果需要使用,需要在配置文件中開啟:
<property name="cache.use_query_cache">true</property>
⑶存儲結構
Query緩存不僅包含查詢結果,而且包含hql語句,搜索Query緩存時,首先對比hql語句,Query緩存只有對完全相同的hql語句可見。
⑷使用
Query q=session.createQuery(hql); List list=q.setCacheable(true).list();