hibernate(持久化)
一. Hibernate 的理解
Hibernate 是資料訪問層(Dao層),就是把資料存入到資料庫中,稱為持久化,
Hibernate 對 JDBC 進行了封裝,針對資料訪問層提出面向物件的思想,操作物件間接的操作資料庫中的表,自動生成 SQL 陳述句,可以簡化資料訪問層的代碼,提高開發效率,
二. hibernate的優缺點
-
優點:
-
使用 JDBC 遇到的問題:
-
代碼中存在大量的 SQL 陳述句
-
查詢結果需要手動封裝到 Model
-
SQL 陳述句中存盤大量的
?,需要手動賦值 -
SQL 陳述句根據不同的資料庫,有不同的函式,如果更換資料庫,需要大量更改 SQL 陳述句,針對資料庫移植性差
-
-
使用 Hibernate 可以解決以上問題:
-
Hibernate 操作物件自動生成 SQL 陳述句
-
查詢結果自動賦值給 Model 類
-
自動賦值
-
Hibernate 使用的是 HQL 陳述句,根據不同的方言,生成不同資料庫的 SQL 陳述句,到達跨資料庫平臺
注:資料遷移是軟性專案中的大事情,特別難做,做專案時對資料庫的選型尤為重要
-
-
-
缺點:
- SQL陳述句自動生成,人工無法控制,使得 SQL 陳述句執行效率慢
- Hibernate 執行效率低
- Hibernate 特別耗記憶體,有一系列快取機制
三. 什么是ORM(☆)
ORM 是一種編程思想(開發模式),全稱:Object Relation Mapper(物件關系映射)
是為了解決面向物件與面向關系型資料庫不匹配現象,通過一個組態檔把面向物件與面向關系型資料庫關聯起來
- 類 --- 表
- 屬性 --- 欄位
- 物件 --- 記錄
優點:使得資料訪問層更面向物件,不用考慮關系型資料庫,只要會面向物件即可,開發程式變簡單了(Hibernate、MyBatis、Spring、JDBC)
四、搭建 Hibernate 環境
- 導包:在
hibernate-release-4.3.11.Final/lib/required下所有 Jar 檔案與資料庫驅動包復制到專案中 - 引入 Hibernate 主組態檔,
Hibernate.cfg.xml檔案復制到專案中的 src 目錄 - 創建一個 Model 類實作 Serializable 介面,對應一個表,并且在映射檔案
xxx.hbm.xml中配置 - 撰寫 Hibernate API 進行測驗
五. Hibernate 的體系結構(Hibernate由哪幾部分組成)(☆)
| 結構 | 描述 |
|---|---|
| hibernate.cfg.xml | 是 Hibernate 的主組態檔,用來配置資料庫連接資訊與 Hibernate 相關引數 |
| XXX.hbm.xml | 類與表之間的映射檔案,一個類對應一個表,一個屬性對應一個欄位 |
| 物體類 | 用于封裝資料庫的表,一定要實作 Serializable 介面 |
| Hibernate API | 用于讀取并決議組態檔,然后根據映射關系生成 SQL 陳述句,間接操作資料庫 |
六. Hibernate 作業原理(☆)
- Configuration 類讀取并決議組態檔(主組態檔、映射檔案)
- 創建 SessionFactory(一個 SessionFactory 對應一個資料庫)
- 打開 Session(Session 代表程式與資料庫之間的一次會話,用來做表的增刪改查)
- 創建事務(Transaction 代表資料庫事務)
- 持久化操作(增刪改查)
- 提交事務
- 關閉 Session
- 當應用程式停止,關閉 SessionFactory
注:SessionFactory 是一個重量級物件,創建銷毀特別耗資源,應用程式創建一次,關閉一次
七. Hibernate 代碼作業原理
-
獲取 Configuration 類的物件(cfg)
-
呼叫
cfg.configure()方法默認讀取 src 根目錄下的hibernate.cfg.xml -
呼叫
cfg.buildSessionFactory()方法創建 Session 工廠(sf) -
呼叫
sf.openSession()方法獲取 Session -
若為添加、洗掉、修改操作,則開啟事務
Transaction ts = session.getTransaction() ts.begin(); -
進行持久化操作
添加:e(obj); 洗掉:delete(obj); 修改:update(obj); 查詢:get(類名.class, 1); 查詢:load(類名.class, 1); 添加和修改都支持:saveOrUpdate(obj); -
提交事務,關閉 Session,關閉 SessionFactory
ts.commit(); session.close(); sf.close();
八. Hibernate 的映射型別
Hibernate 映射檔案xxx.hbm.xml中,Java 資料型別與資料庫資料型別相互轉換,通過 type 屬性進行指定,型別如下:
-
整數
Java 型別 type 取值 byte byte short short int Integer long long -
小數
Java 型別 type 取值 float float double double -
字串
Java 型別 type 取值 String String -
日期
Java 型別 type 取值 java.util.Date date java.sql.Date date -
時間
Java 型別 type 取值 java.sql.Timestamp timestamp
注:建議手動創建表,不要讓 Hibernate 生成表格,
hibernate.hbm2ddl.auto配置成為 update
九. Hibernate 核心開發介面(常用的類與介面)(☆)
| 介面 | 描述 |
|---|---|
| Configuration | 讀取并決議組態檔,然后創建 SessionFactory(是一個類) |
| SessionFactory | 代表一個資料庫,一個 SessionFactory 對應一個資料庫,用于創建 Session(是一個介面) |
| Session | 程式與資料庫的一次會話,用于資料庫表的增刪改查(是一個介面) |
| Transaction | 事務管理(是一個介面) |
| Query 與 Criteria | 用于資料查詢(是一個介面) |
十. Hibernate 有多少種查詢
- 主鍵查詢:
get()與load() - HQL 查詢
- SQL 查詢
- QBC 查詢
查詢效率由高到低排列:主鍵查詢 > SQL 查詢 > HQL 查詢 > QBC 查詢
十一. 查詢方法延遲加載(☆)
-
什么是延遲加載?
Hibernate 中存在一些方法,在查詢的時候并沒有馬上發送 SQL 陳述句去資料庫查詢,而是回傳一個空值物件,空值物件不是 null,而是新 new 出來的物件,除主鍵以外其他屬性值為空,當程式真正使用到此物件時,才會發送 SQL 陳述句去資料庫中查詢,并且將結果賦值給此物件,這種查詢稱為延遲加載
-
為什么要用延遲加載?
- 在延遲的這段時間內,并沒有訪問資料庫,可以節約記憶體開銷,減少資料庫的訪問,提高使用效率
- 可以防止查詢物件,但并沒有真正的使用,這種情況下可以節約記憶體,減少資料庫訪問
-
如何使用延遲加載?
-
Hibernate 中一些方法自帶延遲加載機制,只要呼叫這些方法,就可以使用延遲加載
-
具有延遲加載機制的訪問如下
延遲加載 立即加載 session.load() session.get() query.iterate() query.list()
-
-
get() 與 load() 區別(☆)
get():立即加載,立即發送 SQL 陳述句查詢,如果沒有查詢到結果回傳 null
load():延遲加載,不會立即發送 SQL 陳述句查詢,回傳一個空值物件,真正使用到此物件,才會發送 SQL 陳述句,如果沒有查詢到結果,會拋出
ObjectNotFoundException例外 -
list() 與 iterate() 區別
list():立即加載,立即發送 SQL 陳述句查詢,回傳一個物件集合,如果沒有查詢到資料,回傳空集合
iterate():延遲加載,首先會發送一條 SQL 陳述句把表中所有主鍵查詢出來,在遍歷的時候,根據主鍵發送 SQL 陳述句單個查詢,有多少條記錄就會發送多少條 SQL 陳述句查詢
注:建議使用立即加載
十二. 一級快取(☆)
-
什么是一級快取?
Hibernate 在創建 Session 的時候,會給每個 Session 另外分配一片記憶體空間,用于快取 Session 操作過的物件,這塊兒記憶體稱為一級快取,一級快取是
Session 管理并且使用的,所以也稱為:Session 快取,
一級快取的生命周期與 Session 一致,Session 被創建時,一級快取空間被分配,
session.close()時,一級快取被回收 -
一級快取的作用?
一級快取用來快取 Session 操作過的物件,相同資料不用每次都去查詢資料庫,直接從一級快取中獲取,提高查詢效率
-
一級快取的步驟?
Session 優先查詢一級快取,首先去一級快取中查詢,查詢不到才會發送 SQL 陳述句查詢資料庫,查詢到結果之后會在一級快取中存放一份,再次查詢時,無需發送 SQL 陳述句查詢資料庫,直接從一級快取中獲取(在 Hibernate 中一級快取優先于資料庫,一級快取與資料庫資料不同步時,以一級快取為主)
-
如何使用一級快取?
-
一級快取是默認開啟,自動使用
-
一級快取的特征:
- 一級快取是 Session 獨享的,Session 與 Session 之間不能共享資料
- Session 查詢一組資料時,會將一組資料拆開存入一級快取中,一級快取中存盤的是單個物件
- 執行增刪改時會同步一級快取,當
delete(Object obj)時,在一級快取中會標記此物件可能被洗掉,再次查詢時不會發送 SQL 陳述句查詢,回傳一個null 物件
-
管理快取
- clear():清空一級快取
- evict():清空一級快取單個物件
- flush():手動同步一級快取與資料庫,資料不一樣,以一級快取為主
-
十三. 二級快取
SessionFactory 級別的快取(需要配置)
Hibernate 二級快取需要配置,在同一 SessionFactory 范圍內,查詢同一個物件多次,只會發送一條 SQL 陳述句(只會去資料庫中查詢一次),后面每次查詢都是從二級快取中去取資料
配置資訊:
- 匯入二級快取的 Jar 包 ehcache oscache
- 把對應組態檔放入到 src 根目錄下
- 在
Hibernate.cfg.xml中開啟二級快取 - 宣告哪些物件需要放入到二級快取中
十四. 物件的持久性
什么是物件的持久性?
? Hibernate 操作物件時,可以把物件看成三種狀態::瞬時態,持久臺,游離態/托管態
三種狀態的規則?
-
瞬時態(transient)
- 定義:物件剛剛被 new 出來,稱為瞬時態
- 規則:瞬時態可以被垃圾回識訓制回收,一級快取中沒有,資料庫中沒有
-
持久態(persistent)
- 定義:一級快取中有,資料庫中有,稱為持久態
- 規則:通過 save(),update(),saveOrUpdate(),get(),load(),HQL,SQL,QBC 方式操作過的物件,稱為持久態物件
-
游離態(detached)
- 定義:一級快取中沒有,資料庫中有,稱為游離態
- 規則:通過 clear,evict,close 方式操作過的物件, 稱為游離態物件
十五. 主鍵的生成策略
在映射檔案(xxx.hbm.xml)中需要配置主鍵欄位,并且需要配置主鍵的生成策略,通過 generator 標簽指定
主鍵生成策略:
-
sequence
代碼如下:
<generator > <!-- 指定序列的名稱 --> <param name="sequence">t_person_seq</param> </generator>對應資料庫:Oracle,DB2
-
identity
代碼如下:
<generator ></generator>對應資料庫:MySQL,SQL Server
-
native
代碼如下:
<generator ></generator>含義:native 是讓 hibernate 自動選擇一種主鍵方式,根據組態檔中的方言,從 sequence 與 identity 中選一個,方言配置的是 Oracle ,自動選擇sequence,方言配置的是MySQL,自動選擇 identity
-
assigned
代碼如下:
<generator ></generator>含義:程式員手動分配主鍵,Hibernate 不會自動生成
-
uuid
代碼如下:
<generator ></generator>含義:采用 UUID 演算法生成一個32位十六進制的字串作為主鍵
-
increment
代碼如下:
<generator ></generator>含義:查詢表中最大 id 值, 把最大 id + 1 生成主鍵
優點:適用與任何資料庫
缺點:并發量大時,會產生相同的 id,執行緒不安全,不推薦使用
十六. 關系映射
什么是關系映射?
? 如果兩張表之間有關系,Hibernate 允許我們將關系提取出來,并且映射的組態檔中,在對一個表的增刪改查操作,Hibernate 通過這個映射關系,間接的操作另一張表的增刪改查,這兩個表的關系配置稱為關系映射
關系映射型別?
- 多對一
- 一對多
- 一對一
- 多對多
十七. 多對一(重點)與一對多
-
設計
兩張表之間的關系為多對一或一對多,會在多的一端增加一個欄位指向一的那端的主鍵
-
案例
學生與班級:多個學生屬于一個班級,一個班級有多個學生
一對多添加會產生 N+1 條,盡量少用一對多,用多對一代替
一對多配置:
<!-- set標簽:指定是 set 集合 name屬性:類中的屬性名 --> <set name="students"> <!-- key標簽:指定兩個表之間關聯欄位(外鍵欄位名稱) column屬性:外鍵欄位的欄位名 --> <key column="f_classId"></key> <!-- one-to-many標簽:表示與哪個類發生了一對多的關系 class屬性:多對那端類的名稱 --> <one-to-many /> </set>多對一配置:
<!-- many-to-one 標簽:多對一關系 name 屬性:類中屬性的名稱 column 屬性:表中的欄位名(外鍵欄位名) class 屬性:外鍵屬性的類(完整路徑) --> <many-to-one name="cla" column="f_classId" ></many-to-one>
十八. 關聯操作
關聯查詢(查詢)
-
延遲加載(對于關聯屬性,Hibernate 默認采用的是延遲加載,查詢一端資料,不會關聯出另一端資料)
lazy="proxy/true" 默認方式,采用懶加載 lazy="false" 立即加載,關聯的表資料會同時查詢出來 -
連接查詢
fetch="select" 默認方式,使用多條 SQL 陳述句查詢 fetch="join" 使用連接查詢,一條 SQL 陳述句完成查詢,使用此屬性懶加載失效 -
join 查詢
String hql = "from Student s left join fetch s.cla"; 左外連接 String hql = "from Student s inner join fetch s.cla"; 內連接
級聯操作(增刪改)
-
什么是級聯操作?
在對一張表做增刪改操作時,關聯的另一張表也做增刪改操作,稱為級聯操作
-
如何設定級聯操作?
在映射檔案中,關聯映射配置 cascade 屬性,用這個屬性定義級聯操作
-
cascade取值如下:
| 取值方式 | 描述 |
|---|---|
| none | 默認方式,不支持級聯 |
| all | 支持增刪改 |
| save-update | 支持增,改 |
| delete | 支持刪 |
十九. 一對一(了解)
一對一的型別:
? 主鍵一對一:包裝兩個標段主鍵相同
? 外鍵一對一:在任意一端增加一個欄位(外鍵欄位)指向另一端的主鍵,并且這個欄位有唯一約束(不能重復)
案例:
? 學生與檔案一對一,在學生表中增加一個欄位指向檔案表的主鍵,外鍵保證唯一性
二十. 多對多
什么是多對多?
? 如果兩張表的關系是多對多,必然產生一張中間表,中間表只有兩個欄位,分別為兩張表的外鍵欄位,這兩個外鍵欄位組合成復合主鍵
案例:
? 一個班級由多個老師教學,一個老師可以教多個班級
多對多配置:
<!--
set標簽:指定是 set 集合
name屬性:類中的屬性名
table:中間表的表名
-->
<set name="teachers" table="t_cla_tea">
<!--
column屬性:當前表的主鍵的對應中間表的外鍵欄位
-->
<key column="f_classId"></key>
<!--
many-to-many標簽:多對多的關系映射
class屬性:當前 set 集合元素對應的類名
column屬性:對方表的主鍵對應中間表的外鍵欄位名
-->
<many-to-many column="f_teacherId"/>
</set>
二十一. Hibernate 查詢陳述句
- 主鍵查詢:load,get
- HQL 查詢(Hibernate Query Language) :標準的SQL + 面向物件語言
- QBC 查詢(Query By Criteria):完全的面向物件
- SQL 查詢(Structured Query Language):結構化查詢語言
本文來自博客園,作者:Schieber,轉載請注明原文鏈接:https://www.cnblogs.com/xiqingbo/p/java-24.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/447002.html
標籤:Java
下一篇:一,Flink快速上手
