1. 程式人生 > >【Hibernate(二)】持久化類、主鍵生成策略和一級快取

【Hibernate(二)】持久化類、主鍵生成策略和一級快取

1.2 持久化類的編寫規則

1.2.1 持久化類的概述

什麼是持久化類

持久化:將記憶體中的一個物件持久化到資料庫中過程。Hibernate框架就是用來進行持久化的框架。

持久化類:一個Java物件與資料庫的表建立了對映關係,那麼這個類在Hibernate中稱為是持久化類。

持久化類 = Java類 + 對映檔案

1.2.2 持久化類的編寫規則

持久化類的編寫規則

對持久化類提供一個無參的構造方法:Hibernate底層需要使用反射生成例項。

屬性需要私有,對私有屬性提供public的get和set方法:Hibernate中獲取、設定物件的值。

對持久化類提供一個唯一標識OID與資料庫的主鍵相對應:Java中通過物件的地址區分是否是同一個物件,資料庫中通過主鍵確定是否是同一個記錄,在Hibernate中通過持久化類的OID的屬性區分是否是同一個物件。

持久化類中屬性儘量使用包裝類的型別:因為基本型別預設值是0,那麼0就會有很多的歧義。包裝型別預設值是null。

持久化類不要使用final進行修飾:延遲載入本身是hibernate一個優化的手段,返回的是一個代理物件(javassist可以對沒有實現介面的類產生代理——使用了非常底層位元組碼增強技術,繼承這個類進行代理)。如果不能被繼承,不能產生代理物件,延遲載入也就失效。load方法和get方法一致。

1.3 主鍵生成策略

1.3.1 主鍵的分類

自然主鍵

自然主鍵:主鍵的本身就是表中的一個欄位(實體中的一個具體的屬性)。

      建立一個人員表:人員都會有一個身份證號(唯一的不可重複的),使用了身份證號作為主鍵,這種主鍵稱為是自然主鍵。

代理主鍵

代理主鍵:主鍵的本身不是表中必須的一個欄位(不是實體中的某個具體的屬性)。

      建立一個人員表:沒有使用人員中的身份證號,用了一個與這個表不相關的欄位ID、(PNO),這種主鍵稱為是代理主鍵。

在實際的開發當中,儘量使用代理主鍵。

      一旦自然主鍵參與到業務邏輯當中,後期有可能需要修改原始碼。

      好的程式設計滿足OCP原則,對程式的擴充套件是open的,對修改原始碼是close的。

1.3.2 主鍵的生成策略

Hibernate的主鍵生成策略

在實際的開發中一般不允許使用者手動設定主鍵,一般將主鍵交給資料庫,手動編寫程式進行設定。在hibernate中為了減少程式編寫,提供了很多中的主鍵的生成策略。

increment:hibernate中提供的自動增長機制,適用short、int、long型別的主鍵。在單執行緒程式中使用。

      首先先發送一條語句:select max(id) from 表;然後讓id+1 作為下一條記錄的主鍵。

identity:適用於short、int、long型別的主鍵,使用的是資料庫底層的自動增長機制。適用於有自動增長機制的資料庫(MySQL、MSSQL),但是Oracle是沒有自動增長。

sequence:適用於short、int、long型別的主鍵,採用的是序列的方式。(Oracle支援序列)。像MYSQL就不能使用sequence。

uuid:適用於字串型別的主鍵。使用hibernate中的隨機方式生成字串主鍵。

native:本地策略,可以在identity和sequence之間進行自動切換。

assigned:hibernate放棄外來鍵的管理,需要通過手動編寫程式或者使用者自己設定。

foreign:外部的。一對一的一種關聯對映的情況下使用。(瞭解)

1.4 持久化類的三種狀態

1.4.1 持久化類的三種狀態

Hibernate是持久層框架,通過持久化類完成ORM操作,Hibernate為了更好的管理持久化類,將持久化類分成三種狀態。

持久化類 = Java類 + 對映

瞬時態(transient)

這種物件沒有唯一的標識OID,沒有被session管理,稱為是瞬時態物件。

持久態(persistent)

這種物件有唯一標識OID,被session管理,稱為是持久態物件。

脫管態(detached)

這種物件有唯一標識OID,沒有被session管理,稱為脫管態物件。

區分三種狀態物件

public class HibernateDemo2 {
    @Test
    //三種狀態的區分
    public void demo1(){
        Session = session = HibernateUtils.openSession;
        Transaction = transaction = session.beginTransaction();

        Customer customer = new Customer();//瞬時態物件:沒有唯一標識OID,沒有session管理
        customer.setCust_name("王東");

        Serializable id = session.save(customer);//持久態物件:有唯一標識OID,被session管理

        transaction.commit();
        session.close();

        System.out.println("客戶名稱:"+ customer.getCust_name());//脫管物件:有唯一標識OID,沒有被session管理
    }
}

1.4.2 持久化類的狀態轉換

三種狀態的轉換圖

瞬時態物件

獲得

Customer customer = new Customer();

狀態轉換

瞬時==》持久

      save()、saveOrUpdate(Object obj);

瞬時==》託管

      customer.setCust_id(1l);

持久態物件

獲得

      get()、load()、find()、iterate()

      Customer customer = session.get(Customer.class,1l);

狀態的轉換

持久==》瞬時

      delete()

持久==》脫管

      close()、clear()、evict(Object obj);

脫管態的物件

獲得

Customer customer = new Customer();
customer.setCust_id(1l);

狀態的轉換

脫管==》持久

      update()、saveOrUpdate()

脫管==》瞬時

customer.setCust_id(null);

1.4.3 持久態物件特性

持久化類持久態物件自動更新資料庫

@Test
//持久態物件自動更新資料庫
public void demo2(){
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();
    
    //獲得持久態物件
    Customer customer = session.get(Customer.class,1l);
    customer.setCust_name("王西");
    //session.update(customer);

    transaction.commit();
    session.close();
}

1.5 Hibernate的一級快取

1.5.1 快取的概述

什麼是快取

快取:是一種優化的方式,將資料存入到記憶體中,使用的時候直接從快取中獲取,不用通過儲存源。

1.5.2 Hibernate的快取

HIbernate的一級快取

HIbernate框架中提供了優化手段,快取、抓取策略。Hibernate中提供了兩種快取機制:一級快取、二級快取。

Hibernate的一級快取:稱為是session級別的快取,一級快取生命週期與session一致(一級快取是由session中的一系列的Java集合構成)。一級快取是自帶的不可解除安裝的。(Hibernate的二級快取是SessionFactory級別的快取,需要配置的快取)。

證明一級快取存在

public class HibernateDemo3 {
    @Test
    //證明一級快取的存在
    public void demo1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        Customer customer1 = session.get(Customer.class,1l);//傳送SQL語句
        System.out.println(customer1);

        Customer customer2 = session.get(Customer.class,1l);//不傳送SQL語句
        System.out.println(customer2);

        System.out.println(customer1 == customer2);
        tx.commit();
        session.close();
    }
}

1.5.3 Hibernate的一級快取的結構

一級快取中的特殊區域:快照區

@Test
//一級快取的快照區
public void demo2(){
    Session session = new HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();

    Customer customer = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
    customer.setCust_name("王鳳");

    tx.commit();
    session.close();
}

一級快取的清空

@Test
//一級快取的快照區
public void demo3(){
    Session session = new HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();

    Customer customer1 = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
   
    session.clear();//清空所有
    //session.evict(customer1);

    Customer customer2 = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
    System.out.println(customer1);
    System.out.println(customer2);

    tx.commit();
    session.close();
}

1.6 HIbernate的事務管理

1.6.1 事務的回顧

什麼是事務

事務:事務指的是邏輯上的一組操作,組成這組操作的各個邏輯單元要麼全部成功,要麼全部失敗。

事務特性

原子性:代表事務不可分割。

一致性:代表事務執行的前後,資料的完整性保持一致。

隔離性:代表一事務執行的過程中,不應該受到其他事物的干擾。

永續性:代表事務執行完成後,資料就持久到資料庫中。

如果不考慮隔離性,引發安全性問題

讀問題

      髒讀:一個事務讀到另一個事務未提交的資料。

      不可重複讀:一個事務讀到另一個事物已經提交的update資料,導致在前一個事務多次查詢結果不一致。

      虛讀:一個事務讀到另一個事務已經提交的insert資料,導致在前一個事務多次查詢結果不一致。

寫問題

       引發兩類丟失更新

讀問題的解決

設定事務的隔離級別

      read uncommited:以上的讀問題都會發生    1

      read commiited:解決髒讀,但是不可重複讀和虛讀有可能發生    2

      repeatable read:解決髒讀和不可重複讀,但是虛讀有可能發生    4

      serializable:解決所有讀問題    8

1.6.2 HIbernate中設定事務隔離級別

<!-- 核心配置檔案 設定事務隔離級別 -->
<property name="hibernate.connection.isolation">4</property>

1.6.3 Service層事務

Hibernate解決Service的事務管理

改寫工具類

public class HibernateUtils {
    public static final Configuration cfg;
    public static final SessionFaction sf;

    static {
        cfg = new Configuration().configure();
        sf = cfg.buildSessionFactory();
    }

    public static Session openSession(){
        return sf.openSession();
    }

    public static Session getCurrentSession(){
        return sf.getCurrentSession();
    }
}

配置完成

<!-- hibernate核心配置檔案中 配置當前執行緒繫結的Session -->
<property name="hibernate.current_session_context_class">thread</property>
//測試當前執行緒繫結的Session

public class HibernateDemo4 {
    @Test
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        Customer customer = new Customer();
        customer.setCust_name("王西");
        session.save(customer);

        tx.commit();
    }
}

1.7 Hibernate 的其他API

1.7.1 Query

Query介面用於接收HQL,查詢多個物件。

      HQL:Hibernate Query Language,這種語言與SQL的語法極其類似

//Hibernate的其他API
public class HibernateDemo5 {
    @Test
    //Query
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        //通過Session獲得Query介面
        //簡單查詢
        //String hql = "from Customer";
        //條件查詢
        //String hql = "from Customer where cust_name like ?";
        //分頁查詢
        String hql = "from Customer";
        Query query = session.createQuery(hql);
        //設定條件
        //query.setParameter(0,"王%");
        //設定分頁
        query.setFirstResult(0);
        query.setMaxResullt(3);

        List<Customer> list = query.list();
        for(Customer customer : list) {
            System.out.println(customer);
        }

        tx.commit();
    }
}

1.7.2 Criteria

Criteria:QBC(Query By Criteria)

更加面向物件的查詢方式

@Test
public void demo2(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tx = session.beginTransaction();

    //通過session獲得Criteria的物件
    //Criteria criteria = session.createCriteria(Customer.class);
    //List<Customer> list = criteria.list();

    //條件查詢
    //Criteria criteria = session.createCriteria(Customer.class);
    //criteria.add(Restrictions.like("cust_name","王%"));

    Criteria criteria = session.createCriteria(Customer.class);
    criteria.setFirstResult(3);
    criteria.setMaxResults(3);
    List<Customer> list = criteria.list();

    for(Customer customer : list){
        System.out.println(Customer);
    }

    tx.commit();
}

1.7.3 SQLQuery

SQLQuery用於接收SQL。特別複雜的情況下使用SQL。