一、持久化類的編寫規則
1、持久化類的概述
持久化:將記憶體中的一個物件持久化到資料庫中的過程.Hibernate 框架就是用來持久化的框架
持久化類:一個 Java 類與資料庫中的表建立對映關係.那麼這個類在 Hibernate 中稱為持久化類
持久化類 = Java 類 + 對映檔案
2、持久化類的編寫規則
- 對持久化類提供一個無參構造方法 :Hibernate 底層需要使用反射生成例項
- 屬性需要私有,私有的屬性提供 get 和 set 方法 :Hibernate 中獲取、設定物件的值
- 對持久化類提供一個唯一標識 OID 與資料庫主鍵對應 :Java 中通過記憶體地址區分是否是同一個
- 物件,資料庫中通過主鍵區分是否為同一條記錄,Hibernate 中通過 OID 區分是否為同一個物件
- 持久化類中屬性儘量使用包裝類 :因為基本資料型別預設值是:0,0有很多歧義.包裝類預設值為 null
- 持久化類不要使用 final 修飾 :延遲載入本身是 Hibernate 的一個優化手段,返回一個代理物件(javassist可以對沒有實現介面的類產生代理--使用類非常底層的位元組碼增強技術,繼承這個類進行代理)。如果不能被繼承,就不能產生代理物件,延遲載入也就失效了。load和 get 方法一致。
二、主鍵生成策略
1、主鍵的分類
-
自然主鍵
自然主鍵:主鍵本身就是表中的一個欄位(實體類中的一個屬性)。建立一個人員表,使用身份證(唯一不可重複)作為主鍵,這種主鍵稱為自然主鍵 -
代理主鍵
代理主鍵:主鍵本身不是表中必須的一個欄位(不是實體中的具體的屬性)。建立一個人員表,不使用身份證作為主鍵,使用不相關的ID作為主鍵,這種主鍵稱為代理主鍵。實際開發中,儘量使用代理主鍵
2、主鍵的生成策略
Hibernate 的主鍵生成策略,在實際開發中一般不允許使用者手動設定主鍵,一般將主鍵交給資料庫,或者手動編寫程式進行設
置。在 Hibernate 中為了減少程式碼編寫,提供了很多種主鍵生成的策略。
-
increment
Hibernate 中提供的自動增長機制,適用 short int lang 型別的主鍵,在單執行緒程式中使用首先傳送一條SQL語句:select max(id) from 表; 然後讓 id+1,作為下一條記錄的主鍵 -
identity
適用 short int lang 型別的主鍵,使用的是資料庫底層的自動增長機制.適用於有自動增長機制的資料庫(MySQL), Oracle 沒有自動增長機制. -
sequence
適用於 short int lang 型別的主鍵,採用序列的方式.(Oracle支援序列),MySQL 不支援序列. -
uuid
適用於字串型別的主鍵,使用 Hibernate 中隨機的方式生成字串主鍵 -
native
本地策略,可以在 identity 和 sequence 之間切換. -
assigned
Hibernate 放棄外來鍵的管理,需要通過手動編寫程式和使用者自己設定. -
foreign
外部的,在一對一的關聯對映情況下使用.
三、持久化類的三種狀態
Hibernate 是持久層的 ORM 框架,專注於資料的持久化工作。在進行資料持久化操作時,持久化物件可能處於不同的狀態當中。這些狀態可分為三種,分別為瞬時態、持久態和脫管態。下面分別針對這三種狀態進行簡單介紹。
1、三種狀態的介紹
-
瞬時態(transient)
瞬時態也稱為臨時態或者自由態,瞬時態的物件是由 new 關鍵字開闢記憶體空間的物件,不存在持久化標識 OID(相當於主鍵值),且未與任何的 Session 例項相關聯,在資料庫中也沒有記錄,失去引用後將被 JVM 回收。瞬時物件在記憶體孤立存在,它是攜帶資訊的載體,不和資料庫的資料有任何關聯關係。 -
持久態(persistent)
持久態的物件存在一個持久化標識 OID,當物件加入到 Session 快取中時,就與 Session 例項相關聯。它在資料庫中存在與之對應的記錄,每條記錄只對應唯一的持久化物件。需要注意的是,持久態物件是在事務還未提交前變成持久態的。 -
脫管態(detached)
脫管態也稱離線態或者遊離態,當持久化物件與 Session 斷開時就變成了脫管態,但是脫管態依然存在持久化標識 OID,只是失去了與當前 Session 的關聯。需要注意的是,脫管態物件發生改變時Hibernate 是不能檢測到的。
2、三種狀態的區分
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import java.io.Serializable;
public class HibernateDemo2 {
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
//瞬時態物件:沒有唯一標識OID,被session 管理
customer.setCust_name("張三丰");
Serializable id = session.save(customer);
//持久態物件:有唯一表示OID,被session 管理
Customer customer2 = session.get(Customer.class,id);
transaction.commit();
session.close();
//託管態物件:有唯一表示OID, 沒有被session管理,session已經close了
System.out.println("客戶名稱:" + customer.getCust_name());
}
}
3、三種狀態轉換
- 三種狀態轉換圖
- 瞬時態物件
獲得
Customer customer = new Customer();
狀態轉換
瞬時 --> 持久
save(Object obj)、saveOrUpdate(Object obj)
瞬時 --> 託管
customer.setCust_id(1L);
- 持久態物件
獲得
get()、load()
狀態轉換
持久 --> 瞬時
delete();
持久 --> 託管
close()、clear()、evict()
- 託管態物件
獲得
Customer customer = new Customer();
customer.setCust_id(1L);
狀態轉換
託管 --> 持久
update()、saveOrUpdate();
託管 --> 瞬時
customer.setCust_id(null);
4、持久態物件的特性
- 持久態物件可以自動更新資料庫
@Test
public void test2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//獲得持久態物件 get load
Customer customer = session.get(Customer.class, 1L);
customer.setCust_name("王娜");
// session.update(customer);
transaction.commit();
session.close();
}
四、Hibernate 的一級快取
1、Hibernate 的一級快取
Hibernate 的一級快取就是指 Session 快取,Session 快取是一塊記憶體空間,用來存放相互管理的Java 物件,在使用 Hibernate 查詢物件的時候,首先會使用物件屬性的 OID 值在 Hibernate 的一級快取中進行查詢,如果找到匹配的 OID 值的物件,就直接將該物件從一級快取中取出使用,不會再查詢資料庫,如果沒有找到相同 OID 值的物件,則會去資料庫中查詢響應資料。當從資料庫中查詢到所需資料時,該資料資訊也會放置到一級快取中。Hibernate 的一級快取的作用就是減少對資料庫訪問的次數。
在 Session 介面的實現中包含一系列的 Java 集合,這些 Java 集合構成了 Session 快取。只要Session 例項沒有結束生命週期,存放在它快取中的物件也不會結束生命週期。固一級快取也被稱為Session 級別的快取。
Hibernate 的一級快取有如下特點:當應用程式呼叫 Session 介面的 sava()、update、saveOrUpdate
2、證明 Hibernate 的一級快取存在
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
/**
* Hibernate 的一級快取
* @ClassName: HibernateDemo3
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo3 {
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer1 = session.get(Customer.class, 1L);
System.out.println(customer1);
Customer customer2 = session.get(Customer.class, 1L);
System.out.println(customer2);
System.out.println(customer1 == customer2);
transaction.commit();
session.close();
}
}
五、Hibernate 事務管理
1、繫結執行緒的 Session
Hibernate5 中自身提供了三種管理 Session 物件的方法
- Session 物件的生命週期與本地執行緒繫結
- Session 物件的生命週期與 JTA 事務繫結
- Hibernate 委託程式管理 Session 物件的宣告週期
在 Hibernate 配置檔案中,hibernate.current_session_context_class 屬性用於指定 Session 管理方式,可選值包括
- thread: Session 物件的生命週期與本地執行緒繫結
- jta: Session 物件的生命週期與 JTA 事務繫結
- managed: Hibernate 委託程式管理 Session 物件的宣告週期
在 hibernate.cfg.xml 配置檔案中進行如下配置:
<!-- 配置 Session 繫結本地執行緒 -->
<property name="hibernate.current_session_context_class">thread</property>
2、修改 HibernateUtils 工具類
/**
* 提供獲得 Session方法
* @return
*/
public static Session getCurrentSession(){
return sessionFaction.getCurrentSession();
}
測試
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("大哥哥");
session.save(customer);
transaction.commit();
//這裡不需要關閉session,因為執行緒結束Session自動銷燬
}
六、Hibernate 的其他 API
1、Query
Query 代表物件導向的一個 Hibernate 操作. 在 Hibernate 中通常使用 session.createQuery() 方法接收一個 HQL 語句,然後使用 query 的 list() 或 uniqueResult() 方法執行查詢. 所謂的 HQL 是Hibernate Query Language 的縮寫,其語法很像 SQL 但是它是完全物件導向的.在 Hibernate 中使用 Query 的步驟:
1. 獲得 Hibernate 的 Session 物件
2. 編寫 HQL 語句
3. 呼叫 session.createQuery() 建立查詢物件
4. 如果 HQL 語句包含引數,則呼叫 Query 的 setXXX 方法設定引數
5. 呼叫 Query 的 list() 或 uniqueResult() 方法執行查詢
- 查詢所有
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import java.util.List;
/**
* 利用Hibernate API 查詢資料庫表
* @ClassName: HibernateDemo4
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo4 {
@Test
public void test1(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer";
Query query = session.createQuery(hql);
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (com.qidishixun.Hibernate.domain.Customer customer :customers){
System.out.println(customer);
}
transaction.commit();
}
}
- 條件查詢
/**
* 模糊查詢
*/
@Test
public void test2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer where cust_name like ?";
Query query = session.createQuery(hql);
query.setParameter(0, "大%");
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (com.qidishixun.Hibernate.domain.Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
- 分頁查詢
/**
* 分頁查詢
*/
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer";
Query query = session.createQuery(hql);
//設定分頁查詢的條件
query.setFirstResult(3); //從幾開始
query.setMaxResults(3); //每頁顯示幾條
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
2、Criteria
Criteria:QBC查詢(Query By Criteria) ,更加物件導向的一種查詢方式
- 查詢所有
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import java.util.List;
/**
* 更加物件導向的一種查詢
* @ClassName: HibernateDemo5
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo5 {
@Test
public void test1(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通過 Session 獲取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
List<com.qidishixun.Hibernate.domain.Customer> customers = criteria.list();
for (com.qidishixun.Hibernate.domain.Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
}
- 條件查詢
@Test
public void test2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通過Session 獲取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
//設定條件
criteria.add(Restrictions.ilike("cust_name","小%"));
List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
for (com.qidishixun.Hibernate.domain.Customer customer : list){
System.out.println(customer);
}
transaction.commit();
}
- 分頁查詢
/**
* 分頁查詢
*/
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通過 Session 獲取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
//設定分頁
criteria.setFirstResult(1); //跳過幾個開始查詢
criteria.setMaxResults(3);
List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
for (Customer customer : list){
System.out.println(customer);
}
transaction.commit();
}
3、SQLQuery
/**
* HQL 和 SQL 的寫法
*/
@Test
public void test4(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list1 = sqlQuery.list();
for (Object[] object : list1){
System.out.println(object.toString());
}
transaction.commit();
session.close();
}