1. 程式人生 > >【吐血整理】Hibernate常用的主鍵生成策略的原理、優缺點、應用場合

【吐血整理】Hibernate常用的主鍵生成策略的原理、優缺點、應用場合

// 此文由老貓燒須整理,其中加上本人的使用教程,如有誤,歡迎指出
// 僅作學習以及備份使用,轉載如帶有本人整理資料請註明出處
// 歡迎大家留言交流

簡介版:

increment:代理主鍵,適合於所有資料庫,由hibernate維護主鍵自增,和底層資料庫無關,但是不適合於2個或以上hibernate程序。【不推薦】

identity:代理主鍵,適合於Mysql或ms sql server等支援自增的dbms,主鍵值不由hibernate維護。

sequence:代理主鍵,適合於oracle等支援序列的dbms,主鍵值不由hibernate維護,由序列產生。

native:代理主鍵,根據底層資料庫的具體特性選擇適合的主鍵生成策略,如果是mysql或sqlserver,選擇identity,如果是oracle,選擇sequence。

hilo:代理主鍵,hibernate把特定表的欄位作為hign值,生成主鍵值

uuid.hex:代理主鍵,hibernate採用uuid 128位演算法生成基於字串的主鍵值

assign:適合於應用程式維護的自然主鍵。

PS.代理主鍵是指與業務無關且能唯一標識資料庫中記錄,一般是資料庫自動生成的,比如mysql可以使用auto_increment,Sql2000可以使用identity生成方式,oracle可以使用sequence生成方式 自然主鍵指業務相關,由使用者指定,且能唯一標識資料庫中的任意一條記錄

//===================================== 分割線,詳細版 =====================================

(1)increment

       a)對主鍵值採取自動順序增長的方式生成新的主鍵,值預設從1開始。

       b)原理:在當前應用例項中維持一個變數,以儲存當前最大值,之後每次需要生成主鍵值的時候將此值加1作為主鍵.不依賴於底層的資料庫,因此所有的資料庫都可以使用

       c)缺點:通過increment的生成主鍵的原理可推斷,此種主鍵生成策略不適用於叢集、同一時段大量使用者併發訪問的系統,既當大量使用者同一時間段同時進行插入操作的時候,可能存在取得相同的最大值然後再同時+1的情況,這個時候就會造成主鍵衝突。因此,如果同一資料庫有多個例項訪問,此方式必須避免使用。

小結:這個是由Hibernate在記憶體中生成主鍵,每次增量為1,不依賴於底層的資料庫,因此所有的資料庫都可以使用,但問題也隨之而來,由於是Hibernate生成的,所以只

能有一個Hibernate應用程序訪問資料庫,否則就會產生主鍵衝突,不能在叢集情況下使用 
插入資料的時候hibernate會給主鍵新增一個自增的主鍵,但是一個hibernate例項就維護一個計數器,所以在多個例項執行的時候不能使用這個方法 

(2)UUID

       a)原理UUID使用128位UUID演算法生成主鍵,能夠保證網路環境下的主鍵唯一性,也就能夠保證在不同資料庫及不同伺服器下主鍵的唯一性。所以使用於所有資料庫。

       b)特點;能夠保證資料庫中的主鍵唯一性,但是在生成的主鍵佔用比較多的存貯空間 

(3)Hilo

      a)原理:通過hi/lo 演算法(Hilo使用高低位演算法生成主鍵,高低位演算法使用一個高位值和一個低位值,然後把演算法得到的兩個值拼接起來)實現的主鍵生成機制,需要額外的資料庫表儲存主鍵生成歷史狀態。

       b)特點:需要額外的資料庫表和欄位提供高位值來源。預設情況下使用的表是   hibernate_unique_key,預設欄位叫作next_hi。next_hi必須有一條記錄否則會出現錯誤。需要額外的資料庫表的支援,能保證同一個資料庫中主鍵的唯一性,但不能保證多個數據庫之間主鍵的唯一性。Hilo主鍵生成方式由Hibernate 維護,所以Hilo方式與底層資料庫無關。

小結:老貓在這裡給大家演示使用方法,也是很簡單的,在hbm對映中:【假設User實體類對應User表】

<!-- 老貓燒須整理 -->
<id column="userId" name="userId" type="int">
			 <generator class="hilo">
			 	<param name="table">需要重新在資料庫中建立的一個使用者存放hilo資料的表</param>
			 	<param name="column">指定的列、欄位</param>
			 	<param name="max_lo">增長值,一般為100</param>
			 </generator>
</id>

執行後,資料庫中User表的主鍵值和獨立的表字段值為
User.userId maxValue
1 1
101 2
202 3
303 4
404 5
不難看出:
主鍵的值 = max_lo * maxValue + maxValue
max_lo(在對映中設定的值)
maxValue(是獨立的表的欄位的記數)

(4)sequence

       a)sequence實際是就是一張單行單列的表。

       b)實現原理:呼叫資料庫中底層存在的sequence生成主鍵,需要底層資料庫的支援序列,因此他是依賴於資料庫的。

       c)支援sequence的資料庫有:Oracle 、DB2(Mysql/SQlServer不支援)、PostgreSql、SAPDb等

小結:DB2、Oracle均支援的序列,用於為long、short或int生成唯一標識 
資料庫中的語法如下: 

Oracle:create sequence seq_name increment by 1 start with 1; 
需要主鍵值時可以呼叫seq_name.nextval或者seq_name.curval得到,資料庫會幫助我們維護這個sequence序列,保證每次取到的值唯一,如: 
insert into tbl_name(id, name) values(seq_name.nextval, ‘Jimliu’);


(5)identity

       a)根據底層資料庫,來支援自動增長,不同的資料庫用不同的主鍵增長方式。如果資料庫沒有在對應的欄位開啟自動增長,則不能插入資料。

       b)特點: 與底層資料庫有關,要求資料庫支援Identity,如MySQl中是auto_increment, SQL Server 中是Identity。支援的資料庫有MySql、SQL Server、DB2、Sybase和HypersonicSQL。

       c)好處:在建表的時候指定了id為自動增長,實際開發中就不需要自己定義插入資料庫的主鍵值,系統會自動順序遞增一個值 。Identity無需Hibernate和使用者的干涉,使用較為方便,但由於依賴於資料庫,所以不便於在不同的資料庫之間移植程式。

小結:適用於MySQL、DB2、MS SQL Server,採用資料庫生成的主鍵,用於為long、short、int型別生成唯一標識 
使用SQL Server 和 MySQL 的自增欄位,這個方法不能放到 Oracle 中,Oracle 不支援自增欄位,要設定sequence(MySQL 和 SQL Server 中很常用)
資料庫中的語法如下: 

MySQL:create table t_user(id int auto_increment primary key, name varchar(20)); 
SQL Server:create table t_user(id int identity(1,1) primary key, name varchar(20));

(6)native

       a)作用:根據資料庫的型別,自動在sequence 、identity和,hilo進行切換。

       b)實現自動切換的依據:根據Hibernate配置檔案中的方言來判斷是Oracle還是Mysql、SqlServer,然後針對資料庫的型別抉擇 sequence還是identity作為主鍵生成策略。

       c)用處:由於Hibernate會根據底層資料庫採用不同的對映方式,因此靈活性高,便於程式移植,專案中如果用到多個數據庫時,可以使用這種方式。

小結:會根據底層資料庫的能力,從identity、sequence、hilo中選擇一個,靈活性更強,但此時,如果選擇sequence或者hilo,則所有的表的主鍵都會從Hibernate預設的sequence或者hilo表中取。並且,有的資料庫對於預設情況主鍵生成測試的支援,效率並不是很高 
對於 oracle 採用 Sequence 方式,對於MySQL 和 SQL Server 採用identity(自增主鍵生成機制),native就是將主鍵的生成工作交由資料庫完成,hibernate不管(很常用) 

(7)assigned

       a)作用:用於手工分配主鍵生成器,一旦指定為這個了,Hibernate就不在自動為程式做主鍵生成器了。沒有指定<generator>標籤時,預設就是assigned主鍵的生成方式

       b)使用方法:在程式中session.save();之前,由程式設計師自己指定主鍵值為多少。

          例如:user.setId(1);這就是在程式中程式設計師手動為使用者表指定主鍵值為1。

(8)foreign

       只適用基於共享主鍵的一對一關聯對映的時候使用。即一個物件的主鍵是參照的另一張表的主鍵生成的。

對資料庫的依賴性總結

   UUID,increment、Hilo、assigned:對資料庫無依賴

    identity:依賴Mysql或sql server,主鍵值不由hibernate維護

    sequence:適合於oracle等支援序列的dbms,主鍵值不由hibernate維護,由序列產生。

    native:根據底層資料庫的具體特性選擇適合的主鍵生成策略,如果是mysql或sqlserver,選擇identity,如果是oracle,選擇sequence。

   關於主鍵生成策略的選擇:

    一般來說推薦UUID,因為生成主鍵唯一,且對資料庫無依賴,可移植性強。

    由於常用的資料庫,如Oracle、DB2、SQLServer、MySql 等,都提供了易用的主鍵生成機制(Auto-Increase 欄位或者Sequence)。我們可以在資料庫提供的主鍵生成機制上,採用native,sequence或者identity的主鍵生成方式。

    不過值得注意的是,一些資料庫提供的主鍵生成機制在效率上未必最佳大量併發insert資料時可能會引起表之間的互鎖。

    因此,對於併發Insert要求較高的系統,推薦採用uuid作為主鍵生成機制。

    總之,hibernate主鍵生成器選擇,還要具體情況具體分析。一般而言,利用uuid方式生成主鍵將提供最好的效能和資料庫平臺適應性。

http://blog.csdn.net/nthack5730