1. 程式人生 > >Hibernate持久化類與主鍵生成策略

Hibernate持久化類與主鍵生成策略

Hibernate持久化類

什麼是持久化類呢?在Hibernate中持久化類的英文名稱是Persistent Object(簡稱PO),PO=POJO+hbm對映配置檔案。
對於Hibernate中的PO,有如下編寫規則:

  1. 必須提供一個無引數的public構造方法。
  2. 所有屬性要用private修飾,對外提供public的get/set方法。
  3. 在PO類必須提供一個標識屬性,讓它與資料庫中的主鍵對應,我們管這個屬性叫OID。
  4. PO類中的屬性儘量使用基本資料型別的包裝類。
  5. PO類不能使用final修飾符。

對於第1、2點,勿須多言,下面我著重解釋一下後面3點。

為何PO類必須提供一個標識屬性OID,讓它與資料庫中的主鍵對應呢?

OID指的是與資料庫中表的主鍵對應的屬性。Hibernate框架是通過OID來區分不同的PO物件,如果在記憶體中有兩個相同的OID物件,那麼Hibernate認為它們是同一個物件。大家理解起來不是很好理解,它涉及到關於Hibernate快取的概念,因為Hibernate是對資料庫直接操作,那麼我們為了優化它呢,肯定提供一些快取的策略。那麼在快取裡面我們怎麼知道這個物件重不重複呢?我們是通過OID來區分的。

為何PO類中的屬性應儘量使用基本資料型別的包裝類?

使用基本資料型別是沒有辦法去描述不存在的概念的,如果使用包裝型別,它就是一個物件,對於物件它的預設值是null,我們知道如果它為null,就代表不存在,那麼它就可以幫助我們去描述不存在的概念。

為何PO類不能使用final修飾符?

要回答這個問題,必須要知道Hibernate中的get/load方法的區別。這也是Hibernate中常考的面試題。我先給出答案:

雖然get/load方法它們都是根據id去查詢物件,但他倆的區別還是蠻大的:
1. get方法直接得到一個持久化型別物件,它就是立即查詢操作,也即我要什麼就查到什麼。load方法它得到的是持久化類的代理型別物件(子類物件)。它採用了一種延遲策略來查詢資料。這時如果PO類使用final修飾符,就會報錯,因為final修飾的類不可以被繼承。
2. get方法在查詢時,如果不存在返回null;load方法在查詢時,如果不存在,會產生異常——org.hibernate.ObjectNotFoundException。

現在就來程式設計釋疑以上這段話,首先我們要搭好Hibernate的開發環境,讀過我前面文章的童鞋,應該可以快速搭建好的,在此不做過多贅述。
在cn.itheima.test包下新建一個單元測試類——HibernateTest.java,我們首先測試Hibernate中的get()方法。

public class HibernateTest {

    // 測試get/load方法的區別
    @Test
    public void test1() {
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 操作
        Customer customer = session.get(Customer.class, 3);
        System.out.println(customer.getClass()); // cn.itheima.domain.Customer

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

測試test1()方法,可以發現Eclipse控制檯列印:

class cn.itheima.domain.Customer

這已說明get()方法直接得到是一個持久化型別物件。
再將get方法改置為load方法,可以發現Eclipse控制檯列印:

class cn.itheima.domain.Customer_$$_jvstd48_0

這似乎說明了load方法得到的是持久化類的代理型別物件(即子類物件)。
現在在這一行上加上一個斷點:

Customer customer = session.get(Customer.class, 3);

然後以斷點模式執行test1()方法,可發現get方法是立即查詢,也即我要什麼就查到什麼。
再將get方法改置為load方法,以斷點模式執行test1()方法,可發現只有當我們訪問物件的get方法時才向資料庫傳送select語句。這已然說明它採用了一種延遲策略來查詢資料。
資料庫中的t_customer表中顯然是沒有id=100的客戶的,而我們就是要查詢這個客戶,可分別試試get/load()方法。這裡也是先測試Hibernate中的get()方法。

public class HibernateTest {

    // 測試get/load方法的區別
    @Test
    public void test1() {
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        // 操作
        Customer customer = session.get(Customer.class, 100);
        System.out.println(customer);

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

測試test1()方法,可以發現Eclipse控制檯列印null,這就說明了get方法在查詢時,如果不存在則返回null
再將get方法改置為load方法,可發現報如下異常:
這裡寫圖片描述
這已然說明了load方法在查詢時,如果不存在,會產生異常org.hibernate.ObjectNotFoundException

Hibernate主鍵生成策略

定義hbm.xml對映檔案和pojo類時都需要定義主鍵,Hibernate中定義的主鍵型別包括自然主鍵和代理主鍵:

  • 自然主鍵(業務主鍵)
    具有業務含義的欄位作為主鍵,比如:學號、身份證號。
  • 代理主鍵(邏輯主鍵)
    不具有業務含義的欄位作為主鍵(例如自增id),比如:mysql自增主鍵,oracle序列生成的主鍵、uuid()方法生成的唯一序列串。

建議:企業開發中使用代理主鍵!

主鍵生成器 描述
increment 代理主鍵。由Hibernate維護一個變數,每次生成主鍵時自動以遞增。問題:如果有多個應用訪問一個數據庫,由於每個應用維護自己的主鍵,所以此時主鍵可能衝突。建議不採用。優點:可以方便跨資料庫平臺。缺點:不適合高併發訪問。
identity 代理主鍵。由底層資料庫生成識別符號。條件是資料庫支援自動增長資料型別。比如:mysql的自增主鍵,oracle不支援主鍵自動生成。如果資料庫支援自增建議採用。優點:由底層資料庫維護,和Hibernate無關。缺點:只能對支援自動增長的資料庫有效,例如mysql。
sequence 代理主鍵。Hibernate根據底層資料庫序列生成識別符號。條件是資料庫支援序列,比如oracle的序列。如果資料庫支援序列建議採用。優點:由底層資料庫維護,和Hibernate無關。缺點:資料庫必須支援sequence方案,例如oracle。
native 代理主鍵。根據底層資料庫自動選擇identity、sequence、hilo,由於生成主鍵策略的控制權由Hibernate控制,所以不建議採用。優點:在專案中如果存在多個數據庫時使用。缺點:效率比較低。
uuid 代理主鍵。Hibernate採用128位的UUID演算法來生成識別符號。該演算法能夠在網路環境中生成唯一的字串識別符號。此策略可以保證生成主鍵的唯一性,並且提供了最好的資料庫插入效能和資料庫平臺的無關性。建議採用。優點:與資料庫無關,方便資料庫移植,效率高,不訪問資料庫就可以直接生成主鍵值,並且它能保證唯一性。缺點:uuid長度大(32位十六進位制數),佔用空間比較大,對應資料庫中char/varchar型別。
assigned 自然主鍵。由java程式負責生成識別符號。不建議採用。儘量在操作中避免手動對主鍵操作。

瞭解上面的知識之後,我來告訴大家怎麼來配置。

  • increment

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="increment"></generator>
    </id>
  • identity

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="identity"></generator>
    </id>
  • sequence

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="sequence"></generator>
    </id>

    如果這樣配置,則預設使用的序列是hibernate_id。但你也可以給其指定一個序列,比如說在Oracle資料庫裡面手動建立了一個序列,在Oracle資料庫中建立一個序列的語法:create sequence 序列名稱; ,則這時就該這麼配置:

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="sequence">
            <param name="sequence">序列名稱</param>
        </generator>
    </id>
  • native

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="native"></generator>
    </id>
  • uuid

    <id name="id" column="id" type="string"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="uuid"></generator>
    </id>

    注意:主鍵的type應是string。

  • assigned

    <id name="id" column="id" type="int"> <!-- java資料型別 -->
        <!-- 主鍵生成策略 -->
        <generator class="assigned"></generator>
    </id>

    注意:儘量在操作中避免手動對主鍵操作。

持久化物件的三種狀態

Hibernate中持久化物件有三種狀態:

  1. 瞬時態:也叫做臨時態或自由態,它一般指我們new出來的物件,它不存在OID,與Hibernate Session無關聯,在資料庫中也無記錄。它使用完成後,會被JVM直接回收掉,它只是用於資訊攜帶。
    簡單說:無OID且與資料庫中的資訊無關聯,不在Session管理範圍內。
  2. 持久態:在Hibernate Session管理範圍內,它具有持久化標識OID。它的特點是在事務未提交前一直是持久態,當它發生改變時,Hibernate是可以檢測到的。
    簡單說:有OID且由Session管理,在資料庫中有可能有,也有可能沒有。
  3. 脫管態:也叫做遊離態或離線態,它是指持久態物件失去了與Session的關聯,脫管態物件它存在OID,在資料庫中有可能存在,也有可能不存在。對於脫管態物件,它發生改變時Hibernet不能檢測到。

接著來測試一下持久化物件的三種狀態,程式碼如下:

public class HibernateTest {

    // 測試持久化物件的三種狀態
    @Test
    public void test2() {
        // 1.得到session
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        Customer c = new Customer(); // 瞬時態(無OID,與session無關聯)
        c.setName("張三");
        c.setSex("男");

        session.save(c); // 建立c與session的關聯關係,它就是持久態的了(有OID)

        // 2.事務提交,並關閉session
        session.getTransaction().commit();
        session.close();

        System.out.println(c.getId()); // 斷開了與session的關聯,它就是脫管態的了(有OID)
    }
}

持久化類三種狀態之間的切換

判斷持久化類物件三種狀態的依據:

  1. 是否有OID
  2. 判斷是否與Session關聯

持久化類物件三種狀態之間的切換可參考下圖:
這裡寫圖片描述
我稍微做一下解釋:

  1. 瞬時態(new出來的)
    瞬時→持久:save()、saveOrUpdate()方法
    瞬時→脫管(遊離):可手動設定oid,但不建議這麼做。如下:

    public class HibernateTest {
    
        // 測試持久化物件的三種狀態
        @Test
        public void test2() {
            // 1.得到session
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
    
            Customer c = new Customer(); // 瞬時態(無OID,與session無關聯)
            c.setName("張三");
            c.setSex("男");
    
            c.setId(7); // 瞬時→脫管(遊離)
            System.out.println(c.getId());
        }
    }
  2. 持久態,它是由Session管理。
    持久→瞬時:delete()——這麼操作以後相當於資料庫裡面就沒有這個記錄了,被刪除後的持久化物件不在建議使用了。
    持久→脫管:注意Session本身是有快取的,它的快取就是所說的一級快取。

    • evict:清除一級快取中指定的一個物件
    • clear:清空一級快取
    • close:關閉,也即清空一級快取
  3. 脫管態(我們要知道它是無法直接獲取的)
    脫管→瞬時:直接將oid刪除(不建議這麼做,因為我們不建議操作脫管態的物件)。如:

    public class HibernateTest {
    
        // 測試持久化物件的三種狀態
        @Test
        public void test2() {
            // 1.得到session
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
    
            Customer c = new Customer(); // 瞬時態(無OID,與session無關聯)
            c.setName("張三");
            c.setSex("男");
    
            c.setId(7); // 瞬時→脫管(遊離)
            c.setId(null); // 脫管(遊離)→瞬時
            System.out.println(c.getId());
        }
    }

    脫管→持久:update、saveOrUpdate、lock(過時),也是不建議這麼做。

相關推薦

(轉) Hibernate持久化生成策略

bject 規則 修飾符 cti arc arch 斷點 可能 策略 http://blog.csdn.net/yerenyuan_pku/article/details/65462930 Hibernate持久化類 什麽是持久化類呢?在Hibernate中持久化類的英

Hibernate持久化生成策略

Hibernate持久化類 什麼是持久化類呢?在Hibernate中持久化類的英文名稱是Persistent Object(簡稱PO),PO=POJO+hbm對映配置檔案。 對於Hibernate中的PO,有如下編寫規則: 必須提供一個無引數的publi

Hibernate(二)】持久化生成策略和一級快取

1.2 持久化類的編寫規則 1.2.1 持久化類的概述 什麼是持久化類 持久化:將記憶體中的一個物件持久化到資料庫中過程。Hibernate框架就是用來進行持久化的框架。 持久化類:一個Java物件與資料庫的表建立了對映關係,那麼這個類在Hibernate中稱為是持久化類。

Hibernate工具生成策略

建立hibernate的好處 1.方便獲取session繪畫,用來操作資料庫 2.用來檢測所有的對映檔案配置是否準確 package com.two.util; import org.hibernate.Session; import org.hibernate.SessionFact

使用註解風格學習Hibernate和JPA的生成策略

                      主鍵是關係資料庫中的一個基本概念,它用來保證記錄的唯一性。簡單來說,就是同一張資料庫表中,不允許存在多條相同主鍵的記錄。主鍵生成策略,就是當向資料庫表中插入記錄的時候,這個記錄的主鍵該如何生成。絕大部分情況下,主鍵都是沒有業務含義的,所以開發者不會、也不需要,顯示地

Hibernate--Increment和Hilo生成策略原理

       最近專案中遇到叢集問題,比如我們有兩個叢集節點,在正常情況下只有一個節點工作(A),當出現異常時切換到另一個叢集節點(B)上。專案中使用Hibernate的increment作為資料庫主鍵生成策略。它的原理如下: Hibernate初始化完成後,當獲取主鍵時,

hibernate實體生成、date日期、列舉型別)

package com.xueyoucto.xueyou; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.Date; /** * Created by Ad

Hibernate各種生成策略配置詳解

文檔 最簡 重啟 如果 自定義 早期 出錯 lsp 當地時間 1、assigned 主鍵由外部程序負責生成,在 save() 之前必須指定一個。Hibernate不負責維護主鍵生成。與Hibernate和底層數據庫都無關,可以跨數據庫。在存儲對象前,必須要使用主鍵的sett

hibernate基礎(三)——生成策略flush快取清理

在瞭解此文前,請首先閱讀: 在使用hibernate時,我們還是很有必要將hibernate的內部實現原理來搞清楚一下的。比如,hibernate在儲存一個物件時, 它的

Hibernate生成策略save()方法是否發sql語句的研究

    public class SessionFlushTest extends TestCase {              /**     * 測試uuid主鍵生成策略     */       public void testSave1() {        

Hibernate 生成策略

關閉 min conn mine 數據 xml文件 ive orm 刪除 第一步:引入jar包 省略 第二部:創建實體類 package cn.hibernate.bean; public class Student { private Integer sId;

Hibernate生成策略小總結

rem 時間值 多線程 class 判斷 acl 選擇 hiberna bsp 主鍵生成策略大致分兩種: 手工控制策略 自動生成策略【框架自動生成和數據庫自動生成】 手工控制策略: assigned:類型是任意的,需要在 save() 到數據庫前,編碼人員手工設置主鍵

Hibernate生成策略

要求 mage src ble 配置 生成策略 padding pac 之前 Hibernate主鍵生成策略 1 hibernate要求實體類裏面有一個屬性作為唯一值,對應表主鍵,主鍵可以不同生成策略 2 hibernate主鍵生成策略有很多的值 3 在cl

Hibernate框架的生成策略

如果 維護 自己 db2 取值 identity 返回 nat 數字   在Hibernate中,id元素的<generator>子元素用於生成持久化類的對象的唯一標識符,也就是主鍵。Hibernate框架中定義了許多主鍵生成策略類,也叫生成器類。所有的生成器類

hibernate框架學習筆記4:生成策略、對象狀態

alt rri gen 線程安全 理論 微軟 unit conf lose 創建一個實體類: package domain; public class Customer { private Long cust_id; private Stri

Hibernate生成策略strategy = "increment"報錯違反唯一性約束

block 一個 blog tps 發現 rate 51cto image 主鍵 背景2018年7月份,系統爆出一條bug。就是支持Excel導入的功能,導入第二次同模板不同數據時,報錯,違反唯一性約束。就死活用不了了,重啟Tomcat才能恢復使用。但只能到一個文件 分析需

Hibernate(2)——IDEA+maven+hibernate生成策略

Maven版本hibernate程式 Pom.xml <dependencies>       <dependency>      

Hibernate自定義生成策略

在沒使用hibernate註解式之前,我們是需要建立hbm.xml的這樣一個用於對映的配置檔案,而我們的主鍵生成的方式則需要在這個xml的檔案內區定義。   黃色框框內就是我們主鍵生成的多種方式 1. <generator class="cok.zking

hibernate入門2生成策略

1. hibernate的主鍵生成器: generator元素:表示了一個主鍵生成器,它用來為持久化類例項生 成唯一的標識 。 1.1 程式設計師自己控制:assigned 1.2 資料庫控制: identity(標識列/自動增長) sequence 1.3 h

hibernate生成策略

1.assigned 程式設計師自己控制:不受資料庫的影響(sid自增長也沒用,得程式設計師自己定義) <generator class="assigned"></generator> 資料型別不限、儲存前必須賦值 2.identity