一、持久化類的編寫規則
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();
}