1. 程式人生 > >Hibernate第二天:Hibernate的一級快取、其他的API

Hibernate第二天:Hibernate的一級快取、其他的API

Hibernate第二天:Hibernate的一級快取、其他的API

 

目錄

Hibernate第二天:Hibernate的一級快取、其他的API

 

 

 

1持久化類的編寫規則

1.2持久化類的編寫規則

2主鍵生成策略

2.1主鍵的分類

2.1.1自然主鍵

2.1.2代理主鍵

2.2主鍵生成策略

3持久化類的三種狀態

3.1持久化類的三種狀態

3.2區分三種狀態物件

3.3持久化類的狀態轉換(瞭解)

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

4Hibernate的一級快取

4.1快取概述

4.2Hibernate快取

4.2.1Hibernate一級快取

4.2.2證明Hibernate一級快取存在

4.2.3Hibernate一級快取結構

5Hibernate的事務管理

5.1什麼是事務

5.2事務的特性

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

5.3讀問題的解決

5.4Hibernate設定事務隔離級別

5.5Hibernate解決Service的事務管理

6Hibernate的其他API

6.1Query

6.2Criteria

6.3SQLQuery


 

1持久化類的編寫規則

1.1什麼是持久化類

 

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

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

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

 

1.2持久化類的編寫規則

  1. 持久化類提供一個無參的構造方法            Hibernate底層需要使用反射生成例項。
  2. 屬性需要私有,對私有屬性提供public的set和get方法:Hibernate中獲取,設定物件的值。
  3. 對持久化類提供一個唯一的標識OID與資料庫主鍵對應:Java中通過物件的地址區是否是同一個物件,資料庫表中通過主鍵繫結是否是同一個記錄,Hibernate中通過持久化類的OID的屬性區分是否是同一個物件。
  4. 持久化類中的屬性,儘量使用包裝類型別:因為基本資料型別預設值是0,會有很多歧義,包裝類預設值為NUll
  5. 持久化類不要用使用final進行修飾:延遲載入本身是hibernate一個優化的手段,返回的是一個代理物件(javassist可以對沒有實現介面的類產生代理-使用了非常底層的位元組碼增強技術,繼承這個類進行代理),如果不能繼承,不能產生代理物件,延遲載入就會失效,load()get()方法一致。

2主鍵生成策略

2.1主鍵的分類

2.1.1自然主鍵

  1. 自然主鍵,主鍵的本身就是表中的一個欄位(實體中的一個具體屬性)。
  1. 建立一個人員表,人員就會有一個身份證號(唯一且不可重複),使用了身份證號作為主鍵,這種主鍵稱為是自然主鍵。

 

 

2.1.2代理主鍵

  1. 代理主鍵,主鍵的本身不是表中必須的一個欄位(不是實體中的某個具體屬性)。
  1. 建立一個人員表,沒有使用人員中的身份證號,用了一個與這個表不相關的欄位ID,(PNO)。這種主鍵稱為是代理主鍵。

在實際開發中,儘量使用代理主鍵,因為一旦主鍵參與到業務邏輯中,後期可能需要修改原始碼。好的程式設計滿足OCP原則,對程式的擴充套件是Open的,對修改原始碼是close的。

 

2.2主鍵生成策略

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

 

  1. Increment :hibernate中提供的自動增長機制,適用short,int,long型別黨的主鍵,在單執行緒中使用。首先發送一條語句,select id  from 表,然後讓id+1作為下一條記錄的主鍵。
  2. Identity:自動增長,適用short,int,long型別的主鍵,使用的是資料庫底層的自動增長,適用於有自動增長機制的資料庫(MySQL,MSSQL),Oracle沒有自動增長。
  3. Sequence:自動增長,適用short,int,long型別的主鍵,採用序列方式(Oracle支援序列)。Mysql不能使用。
  4. UUID:適用於字串型別,使用Hibernate中的隨機方式生成字串主鍵。
  5. Native:本地策略,可以在Identity和Sequence之間進行自動切換。
  6. Assignedhibernate放棄外來鍵管理,需要通過手動編寫程式或者自己設定。
  7. Foreign:外部的,一對一的關聯對映的情況下使用。(瞭解)

 

 

3持久化類的三種狀態

3.1持久化類的三種狀態

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

持久化類=Java類+對映

 

(1)瞬時態(Transient):沒有唯一標識OID,沒有被Session管理。

 

2)持久態(Persistent):有唯一標識OID,被Session管理。

(持久化類的持久態物件,可以自動更新資料庫)

 

(3)脫管態(Detached):有唯一標識OID,沒有被Session管理。

 

3.2區分三種狀態物件

 

@Test

     // 三種狀態區分

     public void demo1() {



         // 1通過工具類獲取Session

         Session session = HibernateUtils.openSession();

         // 2開啟事務

         Transaction tx = session.beginTransaction();

         // 3操作

         // 向資料庫插入一條記錄

         Customer Customer = new Customer(); // 1.瞬時態:沒有位移標識OID(主鍵id),沒有被session管理

    

         Customer.setCust_name("小涵涵"); //             

                                         

         session.save(Customer); // 2.持久太:有唯一標識OID,被session管理

         // 4事務提交 //                                  

         tx.commit(); //                               

         // 5釋放資源 //                                  

         session.close(); //                            

                                

         System.out.println(Customer.getCust_name()); // 3.託管態:有唯一標識OID,沒有被session管理

     }

 

3.3持久化類的狀態轉換(瞭解)

 

  1. 瞬時態:

獲得:由new關鍵字建立

  1. 瞬時態轉換為持久態:執行Session中的save()方法或saveOrUpdate0方法
  2. 瞬時態轉換為脫管態:為瞬時態物件設定持久化標識OID
    Customer customer = new Customer)://瞬時態customersetCust id(1); //脫管態

(2)持久態,
獲得,通過Session的get()、load()方法或者Quey查詢從資料庫中獲得.

  1. 持久態轉換為瞬時態:執行Session中的delete()方法。
  2. 持久態轉換為脫管態:執行Session的evict()、close()或clear()方法用於清除一級快取中某個物件,clear()清除一級快取 中的所有物件。

(3)脫管態,
獲得,脫管態無法獲得,只能由其他狀態轉換而來。

  1. 脫管態轉換為持久態, 執行Session的update()、 saveOrUpdate()或lock()方法。
  2. 脫管態轉換為瞬時態,將脫管態物件的持久化標識OID設定為null

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

@Test

    /****

     * 持久太的物件可以以自動更新資料庫

     */

    public void demo2() {



        // 1通過工具類獲取Session

        Session session = HibernateUtils.openSession();

        // 2開啟事務

        Transaction tx = session.beginTransaction();

        // 3操作

        /** 獲取一個持久太物件了 **/

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

        Customer.setCust_name("王哈哈");

        /** 此處可以省略一個update(如果此處資料和資料庫一樣,不執行Update()) **/

        //session.update(Customer);

        // 4事務提交

        tx.commit();

        // 5釋放資源

        session.close();

    }





4Hibernate的一級快取

4.1快取概述

快取是一種優化的方式,將一些資料放在記憶體,使用的時候直接從快取中獲取,不用通過資料來源。

4.2Hibernate快取

4.2.1Hibernate一級快取

Hibernate一級快取又稱為“Session的快取

Session內建不能被解除安裝,Session的快取是事務範圍的快取(Session物件的生命週期通常對應一個數據庫事務或者一個應用事務)。

一級快取中,持久化類的每個例項都具有唯一的OID

依賴於hibernate一級快取【就是將資料庫/硬碟檔案中資料,放到快取中(就是記憶體中一塊空間),當再次使用時,可以直接從記憶體中獲取資料資訊】。

4.2.2證明Hibernate一級快取存在

@Test

    /****

     * 證明一級快取的存在

     */

    public void demo3() {



        // 1通過工具類獲取Session

        Session session = HibernateUtils.openSession();

        // 2開啟事務

        Transaction tx = session.beginTransaction();

        // 3操作

       

        /**

         * 分別用兩次get執行兩次查詢id=1的客戶,按道理執行兩次get應傳送兩條sql語句,

         * 且Customer1與Customer2不是同一個物件,

         * 實際上只發送一次,且Customer1與Customer2是同一個物件

         * 證明第二次查詢使用的是一級快取中的資料

         **/

        /** 資料庫中第一本書的資訊 **/

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

        System.out.println(Customer1);

        /** 一級快取中中第一本書的資訊 **/

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

        System.out.println(Customer2);

       

        System.out.println(Customer1==Customer2);

        // 4事務提交

        tx.commit();

        // 5釋放資源

        session.close();

    }



 

4.2.3Hibernate一級快取結構

 


 

@Test

    /****

     * 深入瞭解持久態的物件可以以自動更新資料庫

     * 基於一級快取:快照區

     */

    public void demo4() {



       // 1通過工具類獲取Session

       Session session = HibernateUtils.openSession();

       // 2開啟事務

       Transaction tx = session.beginTransaction();

       // 3操作

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

       /** 將資訊儲存於快照區 **/

       Customer.setCust_name("張三丰");// 先將一級快取區的【cust_name】修改為【"張三丰"】-----中間會進行一個比對檢視是否一致,如果一致不更新(不會執行update語句),如果不一致----再將快照區中的【cust_name】修改為【"張三丰"】(執行update語句)。

       // 4事務提交

       tx.commit();

       // 5釋放資源

       session.close();

    }

5Hibernate的事務管理

5.1什麼是事務

 

事務:指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。

5.2事務的特性

1.原子性

(Atomic)(Atomicity)

事務必須是原子工作單元;對於其資料修改,要麼全都執行,要麼全都不執行。

2.一致性

(Consistent)(Consistency)

事務在完成時,必須使所有的資料都保持一致狀態。

3.隔離性

(Insulation)(Isolation)

由併發事務所作的修改必須與任何其它併發事務所作的修改隔離。

4.永續性

(Duration)(Durability)

事務完成之後,它對於系統的影響是永久性的。該修改即使出現致命的系統故障也將一直保持。

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

讀的問題:

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

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

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

 

寫問題(瞭解)

     引發丟失更新。

5.3讀問題的解決

設定事務的隔離級別

   Serializable (序列化):可避免髒讀、不可重複讀、幻讀的發生。

   Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。

   Read committed (讀已提交):可避免髒讀的發生。

   Read uncommitted (讀未提交):最低級別,任何情況都無法保證。

MySQL資料庫中,支援上面四種隔離級別,預設的為Repeatable read (可重複讀);而在Oracle資料庫中,只支援Serializable (序列化)級別和Read committed (讀已提交)這兩種級別,其中預設的為Read committed級別。

5.4Hibernate設定事務隔離級別

核心配置檔案中加入:

<!--  事務隔離級別

            0:TRANSACTION_NONE

            1:TRANSACTION_READ_UNCOMMITTED

            2:TRANSACTION_READ_COMMITTED

            4:TRANSACTION_REPEATABLE_READ

            8:TRANSACTION_SERIALIZABLE

-->

<property name="hibernate.connection.isolation">4</property>

   

 

5.5Hibernate解決Service的事務管理

改寫工具類:

package top.yangxianyang.utils;



import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;



/**

 * Hibernate的工具類

 * @author yxy

 *

 */

public class HibernateUtils {



    public static final Configuration cfg;

    public static final SessionFactory sf;

   

    static{

       cfg = new Configuration().configure();

       sf = cfg.buildSessionFactory();

    }

    /*

     * 提供獲得session的方法

     */

    public static Session openSession(){

       return sf.openSession();

    }

   

    /*

     * 提供獲得session的方法

     */

    public static Session getCurrentSession(){

       return sf.getCurrentSession();

    }

}

核心檔案配置:

<!-- 配置當前執行緒繫結的Session -->

       <property name="hibernate.current_session_context_class">thread</property>

      

程式碼:

package top.yangxianyang.demo1;



import org.hibernate.Session;

import org.hibernate.Transaction;

import org.junit.Test;



import top.yangxianyang.utils.HibernateUtils;





/*

 * Hibernate執行緒繫結Session

 * @author yxy

 *

 */

public class HibernateTest3 {



   

    @Test

    public void demo1(){

       Session session=HibernateUtils.getCurrentSession();

       Transaction tx=session.beginTransaction();

      

       Customer Customer = new Customer();

       Customer.setCust_name("涵涵"); 

      

       session.save(Customer);

      

       tx.commit();

      

    }

}





 

6Hibernate的其他API

6.1Query

1 使用query物件,不需要寫sql語句,但是寫hql語句

(1)hql:hibernate query language,hibernate提供查詢語言,這個hql語句和普通sql語句很相似

(2)hql和sql語句區別:

- 使用sql操作表和表字段

- 使用hql操作實體類和屬性

 

2 查詢所有hql語句:

(1)from 實體類名稱

 

3 Query物件使用

(1)建立Query物件

(2)呼叫query物件裡面的方法得到結果


 

@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.setMaxResults(2);

        List<Customer> list=query.list();

       

        for (Customer customer : list) {

            System.out.println(customer);

        }

       

        tx.commit();

       

    }





6.2Criteria

1使用這個物件時候,不需要寫語句,直接呼叫方法實現,更加面向物件。

2 實現過程

(1)建立criteria物件

(2)呼叫物件裡面的方法得到結果 

   @Test

    //Criteria

    public void demo2(){

       Session session=HibernateUtils.getCurrentSession();

       Transaction tx=session.beginTransaction();

       //通過session獲得Criteria物件

       Criteria ct=session.createCriteria(Customer.class);

       //條件查詢

       ct.add(Restrictions.like("cust_name", "張%"));

       List<Customer> list=ct.list();

       //分頁

       ct.setFirstResult(0);

       ct.setMaxResults(2);

      

      

      

       for (Customer customer : list) {

           System.out.println(customer);

       }

      

       tx.commit();

      

    }

 

6.3SQLQuery

 

1 使用hibernate時候,呼叫底層sql實現

2 實現過程

(1)建立物件

(2)呼叫物件的方法得到結果


 

@Test

    // 查詢所有

    public void demo6(){

        Session session = HibernateUtils.openSession();

        Transaction tx = session.beginTransaction();

       

        // 接收SQL:

        SQLQuery query = session.createSQLQuery("select * from cst_customer");

        List<Object[]> list = query.list();

        for (Object[] objects : list) {

            System.out.println(Arrays.toString(objects));

        }

        tx.commit();

        session.close();

    }







 

今天任務完成。

原始碼地址:

連結:https://pan.baidu.com/s/1rMQ9XBMIeu2O_VbNZBo3MQ 密碼:0hgz