Hibernate學習筆記二

落花桂發表於2021-06-29

一、持久化類的編寫規則

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();
    }

相關文章