【吐血整理】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