JPA Hibernate 使用UUID做為主鍵的問題


1.將數據庫中的主鍵,設置為varchar(32)。

2.在entity中類頭部寫入@GenericGenerator(name = "jpa-uuid", strategy = "uuid")

3.在entity中id主鍵頂部寫入@GeneratedValue(generator = "jpa-uuid"),注意generator中的值必須與注釋@GenericGenerator中name屬性完全一致。

4.設置entity中主鍵ID為string類型。設置長度為32

5.GenericGenerator是Hibernate中的注釋,有兩個參數。name是system-uuid“” ,策略strategy是uuid 。

6.@GenericGenerator支持13種策略,分別是:

static { GENERATORS.put("uuid", UUIDHexGenerator.class); GENERATORS.put("hilo", TableHiLoGenerator.class); GENERATORS.put("assigned", Assigned.class); GENERATORS.put("identity", IdentityGenerator.class); GENERATORS.put("select", SelectGenerator.class); GENERATORS.put("sequence", SequenceGenerator.class); GENERATORS.put("seqhilo", SequenceHiLoGenerator.class); GENERATORS.put("increment", IncrementGenerator.class); GENERATORS.put("foreign", ForeignGenerator.class); GENERATORS.put("guid", GUIDGenerator.class); GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class); } 
上面的12種策略,再加上native,一共是13種。
7.@GeneratedValue注解屬於一個JPA接口(從JAVA EE 5開始,存在於javax.persistence包下),其接口下包含了兩個抽象的參數,GenerationType類型的strategy和String類型的generator,並且兩個參數都有相應的默認值。 

8.GenerationType同樣也位於javax.persistence包下,並且還繼承了Enum枚舉類,然后其中有4個值供我們使用,分別是: 
TABLE:使用一個特定的數據庫表格來保存主鍵。 
SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。 這個值要與generator一起使用,generator 指定生成主鍵使用的生成器(可能是orcale中自己編寫的序列)。 
IDENTITY:主鍵由數據庫自動生成(主要是支持自動增長的數據庫,如mysql) 
AUTO:主鍵由程序控制,也是GenerationType的默認值。

9.兩個數據庫對GenerationType的支持

mysql 
GenerationType.TABLE 
GenerationType.AUTO 
GenerationType.IDENTITY 
不支持GenerationType.SEQUENCE

oracle 
strategy=GenerationType.AUTO 
GenerationType.SEQUENCE 
GenerationType.TABLE 
不支持GenerationType.IDENTITY

 

https://www.cnblogs.com/keeplee/p/9055186.html

 

 

hibernate的id生成策略  

hibernate文檔寫道

1、自動增長identity

適用於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));

<id name="id" column="id" type="long">
  <generator class="identity" />
</id>

 

2、sequence

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’);

<id name="id" column="id" type="long">
  <generator class="sequence">
    <param name="sequence">seq_name</param>
  </generator>
</id>

 

如果我們沒有指定sequence參數,則Hibernate會訪問一個默認的sequence,是hibernate_sequence,我們也需要在數據庫中建立這個sequence
此外,sequence還可以有另外一個參數是paramters,可以查看Hibernate的API了解它的用法,見org.hibernate.id.SequenceGenerator
調用數據庫的sequence來生成主鍵,要設定序列名,不然hibernate無法找到:
<param name="sequence">NAME_SEQ</param>(Oracle中很常用)

3、native(常用)

會根據底層數據庫的能力,從identity、sequence中選擇一個,靈活性更強,如果能支持identity則使用identity,如果支持sequence則使用sequence。例如MySQL使用identity,Oracle使用sequence

但此時,如果選擇sequence,則所有的表的主鍵都會從Hibernate默認的sequence表中取。並且,有的數據庫對於默認情況主鍵生成測試的支持,效率並不是很高
對於 oracle 采用 Sequence 方式,對於MySQL 和 SQL Server 采用identity(自增主鍵生成機制),native就是將主鍵的生成工作交由數據庫完成,hibernate不管(很常用)

<id name="id" column="id">
    <generator class="native" />
</id>

4、assigned(常用)

自己賦值,由應用程序負責生成主鍵標識符,往往使用在數據庫中沒有代理主鍵,使用的主鍵與業務相關的情況,如:

<id name="id" column="id" type="string">
    <generator class="assigned" />
</id>

這種主鍵的生成方式不建議使用,在數據庫表設計時就應該使用代理主鍵(surrogate key),不應使用自然主鍵(natural key具有業務含義),在沒有指定<generator>標簽時,默認就是assigned主鍵的生成方式

在插入數據的時候主鍵由用戶自己添加,hibernate也不管

5、uuid

UUID:Universally Unique Identifier,是指在一台機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。按照開放軟件基金會(OSF)制定的標准計算,用到了以太網卡地址、納秒級時間、芯片ID碼和許多可能的數字,標准的UUID格式為:

xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)   ,  其中每個 x 是 0-9 或 a-f 范圍內的一個十六進制的數字。

<id name="id" column="id">
    <generator class="uuid" />
</id>

Hibernate在保存對象時,生成一個UUID字符串作為主鍵,保證了唯一性,但其並無任何業務邏輯意義,只能作為主鍵,唯一缺點長度較大,32位(Hibernate將UUID中間的“-”刪除了)的字符串,占用存儲空間大,但是有兩個很重要的優點,Hibernate在維護主鍵時,不用去數據庫查詢,從而提高效率,而且它是跨數據庫的,以后切換數據庫極其方便。

特點:uuid長度大,占用空間大,跨數據庫,不用訪問數據庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。不推薦使用guid,所以不再介紹guid

MySQL中使用select uuid()語句獲得的為36位(包含標准格式的“-”)

Oracle中,使用select rawtohex(sys_guid()) from dual語句獲得的為32位(不包含“-”) 

5、項目用到:

安裝有oracle數據庫,創建數據庫,總是要創建一個主鍵ID,唯一標示各條記錄,但oracle不支持自動編號,所以還得創建一個SEQUENCE(序列)語句如
mysql不支持序列 直接@GenericGenerator(name = "generator",strategy = "native")

sql增加序列:
create sequence bign nocycle maxvalue 9999999999 start with1; //增加數據
 
 
liquibase 增加序列:
<changeSet author="zhaoyanhao" id="pub-20190827-001" dbms="oracle">
    <comment>新增序列so_pub_dic_checkopinion</comment>
    <createSequence schemaName="${schema.dlmis}" sequenceName="so_pub_dic_checkopinion" startValue="1" incrementBy="1" />
</changeSet>
為了兼容oracle,對應mapping類的主鍵上使用上邊定義的序列so_pub_dic_checkopinion如下:
@Id
@Column(name = "opinion_id",unique = true,nullable = false)
@GeneratedValue(generator = "generator")
@GenericGenerator(name = "generator",strategy = "native",parameters = {@Parameter(name = "sequence", value = SchemaConst.DLMIS_ + "so_pub_dic_checkopinion")})
private Integer opinionId;

 

https://www.cnblogs.com/zhaoyanhaoBlog/p/11427923.html

 

Hibernate各種主鍵生成策略與配置詳解

1、assigned

主鍵由外部程序負責生成,在 save() 之前必須指定一個。Hibernate不負責維護主鍵生成。與Hibernate和底層數據庫都無關,可以跨數據庫。在存儲對象前,必須要使用主鍵的setter方法給主鍵賦值,至於這個值怎么生成,完全由自己決定,這種方法應該盡量避免。

<id name="id" column="id">

<generator class="assigned" />

</id>

“ud”是自定義的策略名,人為起的名字,后面均用“ud”表示。

特點:可以跨數據庫,人為控制主鍵生成,應盡量避免。

2、increment

由Hibernate從數據庫中取出主鍵的最大值(每個session只取1次),以該值為基礎,每次增量為1,在內存中生成主鍵,不依賴於底層的數據庫,因此可以跨數據庫。

<id name="id" column="id">

<generator class="increment" />

</id>

Hibernate調用org.hibernate.id.IncrementGenerator類里面的generate()方法,使用select max(idColumnName) from tableName語句獲取主鍵最大值。該方法被聲明成了synchronized,所以在一個獨立的Java虛擬機內部是沒有問題的,然而,在多個JVM同時並發訪問數據庫select max時就可能取出相同的值,再insert就會發生Dumplicate entry的錯誤。所以只能有一個Hibernate應用進程訪問數據庫,否則就可能產生主鍵沖突,所以不適合多進程並發更新數據庫,適合單一進程訪問數據庫,不能用於群集環境。

官方文檔:只有在沒有其他進程往同一張表中插入數據時才能使用,在集群下不要使用。

特點:跨數據庫,不適合多進程並發更新數據庫,適合單一進程訪問數據庫,不能用於群集環境。

3、hilo

hilo(高低位方式high low)是hibernate中最常用的一種生成方式,需要一張額外的表保存hi的值。保存hi值的表至少有一條記錄(只與第一條記錄有關),否則會出現錯誤。可以跨數據庫。

<id name="id" column="id">

<generator class="hilo">

<param name="table">hibernate_hilo</param>

<param name="column">next_hi</param>

<param name="max_lo">100</param>

</generator>

</id>

<param name="table">hibernate_hilo</param> 指定保存hi值的表名

<param name="column">next_hi</param> 指定保存hi值的列名

<param name="max_lo">100</param> 指定低位的最大值

也可以省略table和column配置,其默認的表為hibernate_unique_key,列為next_hi

<id name="id" column="id">

<generator class="hilo">

<param name="max_lo">100</param>

</generator>

</id>

hilo生成器生成主鍵的過程(以hibernate_unique_key表,next_hi列為例):

1. 獲得hi值:讀取並記錄數據庫的hibernate_unique_key表中next_hi字段的值,數據庫中此字段值加1保存。

2. 獲得lo值:從0到max_lo循環取值,差值為1,當值為max_lo值時,重新獲取hi值,然后lo值繼續從0到max_lo循環。

3. 根據公式 hi * (max_lo + 1) + lo計算生成主鍵值。

注意:當hi值是0的時候,那么第一個值不是0*(max_lo+1)+0=0,而是lo跳過0從1開始,直接是1、2、3……

那max_lo配置多大合適呢?

這要根據具體情況而定,如果系統一般不重啟,而且需要用此表建立大量的主鍵,可以吧max_lo配置大一點,這樣可以減少讀取數據表的次數,提高效率;反之,如果服務器經常重啟,可以吧max_lo配置小一點,可以避免每次重啟主鍵之間的間隔太大,造成主鍵值主鍵不連貫。

特點:跨數據庫,hilo算法生成的標志只能在一個數據庫中保證唯一。

4、seqhilo

與hilo類似,通過hi/lo算法實現的主鍵生成機制,只是將hilo中的數據表換成了序列sequence,需要數據庫中先創建sequence,適用於支持sequence的數據庫,如Oracle。

<id name="id" column="id">

<generator class="seqhilo">

<param name="sequence">hibernate_seq</param>

<param name="max_lo">100</param>

</generator>

</id>

 

特點:與hilo類似,只能在支持序列的數據庫中使用。

5、sequence

采用數據庫提供的sequence機制生成主鍵,需要數據庫支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL這種不支持sequence的數據庫則不行(可以使用identity)。

<generator class="sequence">

<param name="sequence">hibernate_id</param>

</generator>

<param name="sequence">hibernate_id</param> 指定sequence的名稱

Hibernate生成主鍵時,查找sequence並賦給主鍵值,主鍵值由數據庫生成,Hibernate不負責維護,使用時必須先創建一個sequence,如果不指定sequence名稱,則使用Hibernate默認的sequence,名稱為hibernate_sequence,前提要在數據庫中創建該sequence。

特點:只能在支持序列的數據庫中使用,如Oracle。

6、identity

identity由底層數據庫生成標識符。identity是由數據庫自己生成的,但這個主鍵必須設置為自增長,使用identity的前提條件是底層數據庫支持自動增長字段類型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle這類沒有自增字段的則不支持。

<id name="id" column="id">

<generator class="identity" />

</id>

例:如果使用MySQL數據庫,則主鍵字段必須設置成auto_increment。

id int(11) primary key auto_increment

特點:只能用在支持自動增長的字段數據庫中使用,如MySQL。

7、native

native由hibernate根據使用的數據庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式,靈活性很強。如果能支持identity則使用identity,如果支持sequence則使用sequence。

<id name="id" column="id">

<generator class="native" />

</id>

例如MySQL使用identity,Oracle使用sequence

注意:如果Hibernate自動選擇sequence或者hilo,則所有的表的主鍵都會從Hibernate默認的sequence或hilo表中取。並且,有的數據庫對於默認情況主鍵生成測試的支持,效率並不是很高。

使用sequence或hilo時,可以加入參數,指定sequence名稱或hi值表名稱等,如

<param name="sequence">hibernate_id</param>

特點:根據數據庫自動選擇,項目中如果用到多個數據庫時,可以使用這種方式,使用時需要設置表的自增字段或建立序列,建立表等。

8、uuid

UUID:Universally Unique Identifier,是指在一台機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。按照開放軟件基金會(OSF)制定的標准計算,用到了以太網卡地址、納秒級時間、芯片ID碼和許多可能的數字,標准的UUID格式為:

xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

其中每個 x 是 0-9 或 a-f 范圍內的一個十六進制的數字。

<id name="id" column="id">

<generator class="uuid" />

</id>

Hibernate在保存對象時,生成一個UUID字符串作為主鍵,保證了唯一性,但其並無任何業務邏輯意義,只能作為主鍵,唯一缺點長度較大,32位(Hibernate將UUID中間的“-”刪除了)的字符串,占用存儲空間大,但是有兩個很重要的優點,Hibernate在維護主鍵時,不用去數據庫查詢,從而提高效率,而且它是跨數據庫的,以后切換數據庫極其方便。

特點:uuid長度大,占用空間大,跨數據庫,不用訪問數據庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。

9、guid

GUID:Globally Unique Identifier全球唯一標識符,也稱作 UUID,是一個128位長的數字,用16進制表示。算法的核心思想是結合機器的網卡、當地時間、一個隨即數來生成GUID。從理論上講,如果一台機器每秒產生10000000個GUID,則可以保證(概率意義上)3240年不重復。

<id name="id" column="id">

<generator class="guid" />

</id>

Hibernate在維護主鍵時,先查詢數據庫,獲得一個uuid字符串,該字符串就是主鍵值,該值唯一,缺點長度較大,支持數據庫有限,優點同uuid,跨數據庫,但是仍然需要訪問數據庫。

注意:長度因數據庫不同而不同

MySQL中使用select uuid()語句獲得的為36位(包含標准格式的“-”)

Oracle中,使用select rawtohex(sys_guid()) from dual語句獲得的為32位(不包含“-”) 

特點:需要數據庫支持查詢uuid,生成時需要查詢數據庫,效率沒有uuid高,推薦使用uuid。

10、foreign

使用另外一個相關聯的對象的主鍵作為該對象主鍵。主要用於一對一關系中。

<id name="id" column="id">

<generator class="foreign">

<param name="property">user</param>

</generator>

</id>

<one-to-one name="user" class="domain.User" constrained="true" />

該例使用domain.User的主鍵作為本類映射的主鍵。

特點:很少使用,大多用在一對一關系中。

11、select

使用觸發器生成主鍵,主要用於早期的數據庫主鍵生成機制,能用到的地方非常少。

12、其他注釋方式配置

注釋方式與配置文件底層實現方式相同,只是配置的方式換成了注釋方式

自動增長,適用於支持自增字段的數據庫

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

根據底層數據庫自動選擇方式,需要底層數據庫的設置

如MySQL,會使用自增字段,需要將主鍵設置成auto_increment。

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

使用表存儲生成的主鍵,可以跨數據庫。

每次需要主鍵值時,查詢名為"hibernate_table"的表,查找主鍵列"gen_pk"值為"2"記錄,得到這條記錄的"gen_val"值,根據這個值,和allocationSize的值生成主鍵值。

@Id

@GeneratedValue(strategy = GenerationType.TABLE, generator = "ud")

@TableGenerator(name = "ud",

table = "hibernate_table",

pkColumnName = "gen_pk",

pkColumnValue = "2",

valueColumnName = "gen_val",

initialValue = 2,

allocationSize = 5)

使用序列存儲主鍵值

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ud")

@SequenceGenerator(name = "ud",

sequenceName = "hibernate_seq",

allocationSize = 1,

initialValue = 2)

13、小結

1、為了保證對象標識符的唯一性與不可變性,應該讓Hibernate來為主鍵賦值,而不是程序。

2、正常使用Hibernate維護主鍵,最好將主鍵的setter方法設置成private,從而避免人為或程序修改主鍵,而使用assigned方式,就不能用private,否則無法給主鍵賦值。

2、Hibernate中唯一一種最簡單通用的主鍵生成器就是uuid。雖然是個32位難讀的長字符串,但是它沒有跨數據庫的問題,將來切換數據庫極其簡單方便,推薦使用!

3、自動增長字段類型與序列

數據庫

自動增長字段

序列

MySQL

 

Oracle

 

DB2

MS SQL Server

 

Sybase

 

HypersonicSQL

 

PostgreSQL

 

SAP DB

 

HSQLDB

 

Infomix

 

4、關於hilo機制注意:

hilo算法生成的標志只能在一個數據庫中保證唯一。

當用戶為Hibernate自行提供連接,或者Hibernate通過JTA,從應用服務器的數據源獲取數據庫連接時,無法使用hilo,因為這不能保證hilo單獨在新的數據庫連接的事務中訪問hi值表,這種情況,如果數據庫支持序列,可以使用seqhilo。

5、使用identity、native、GenerationType.AUTO等方式生成主鍵時,只要用到自增字段,數據庫表的字段必須設置成自動增加的,否則出錯。

6、還有一些方法未列出來,例如uuid.hex,sequence-identity等,這些方法不是很常用,且已被其他方法代替,如uuid.hex,官方文檔里建議不使用,而直接使用uuid方法。

7、Hibernate的各版本主鍵生成策略配置有略微差別,但實現基本相同。如,有的版本默認sequence不指定序列名,則使用名為hibernate_sequence的序列,有的版本則必須指定序列名。

8、還可以自定義主鍵生成策略,這里暫時不討論,只討論官方自帶生成策略。 

 

https://www.cnblogs.com/hoobey/p/5508992.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM