數(shù)據(jù)的唯一性是所有應(yīng)用程序非常基本的要求,由開發(fā)者或者用戶來維護(hù)這種唯一性存在著較大的風(fēng)險(xiǎn),因此,由系統(tǒng)自動(dòng)產(chǎn)生唯一標(biāo)識(shí)是一種常見的做法。OpenJPA 中支持四種不同的實(shí)體標(biāo)識(shí)自動(dòng)生成策略:
- 容器自動(dòng)生成的實(shí)體標(biāo)識(shí);
- 使用數(shù)據(jù)庫(kù)的自動(dòng)增長(zhǎng)字段生成實(shí)體標(biāo)識(shí);
- 根據(jù)數(shù)據(jù)庫(kù)序列號(hào)(Sequence)技術(shù)生成實(shí)體標(biāo)識(shí);
- 使用數(shù)據(jù)庫(kù)表的字段生成實(shí)體標(biāo)識(shí);
這四種方式各有優(yōu)缺點(diǎn),開發(fā)者可以根據(jù)實(shí)際情況進(jìn)行選擇。
可選擇的注釋
要讓容器和數(shù)據(jù)庫(kù)結(jié)合管理實(shí)體標(biāo)識(shí)的自動(dòng)生成,根據(jù)實(shí)際情況的不同,開發(fā)者可以選擇 javax.persistence.*
包下面的 GeneratedValue
、SequenceGenerator
、TableGenerator
三個(gè)注釋來描述實(shí)體的標(biāo)識(shí)字段。
@javax.persistence.GeneratedValue
每一個(gè)需要自動(dòng)生成實(shí)體標(biāo)識(shí)的實(shí)體都需要為它的實(shí)體標(biāo)識(shí)字段提供 GeneratedValue
注釋和相應(yīng)的參數(shù),OpenJPA 框架會(huì)根據(jù)注釋和參數(shù)來處理實(shí)體標(biāo)識(shí)的自動(dòng)生成。
使用 GeneratedValue
注釋自動(dòng)生成的實(shí)體標(biāo)識(shí)可以是數(shù)值類型字段如 byte
、short
、int
、long
等,或者它們對(duì)應(yīng)的包裝器類型 Byte
、Short
、Integer
、Long
等,也可以是字符串類型。
GeneratedValue
注釋可以支持兩個(gè)屬性 strategy
和 generator
。
strategy
strategy
是 GenerationType
類型的枚舉值,它的內(nèi)容將指定 OpenJPA 容器自動(dòng)生成實(shí)體標(biāo)識(shí)的方式。strategy
屬性可以是下列枚舉值:
GeneratorType.AUTO
表示實(shí)體標(biāo)識(shí)由 OpenJPA 容器自動(dòng)生成,這也是 Strategy 屬性的默認(rèn)值。
GenerationType.IDENTITY
OpenJPA 容器將使用數(shù)據(jù)庫(kù)的自增長(zhǎng)字段為新增加的實(shí)體對(duì)象賦唯一值,作為實(shí)體的標(biāo)識(shí)。這種情況下需要數(shù)據(jù)庫(kù)提供對(duì)自增長(zhǎng)字段的支持,常用的數(shù)據(jù)庫(kù)中,HSQL、SQL Server、MySQL、DB2、Derby 等數(shù)據(jù)庫(kù)都能夠提供這種支持。
GenerationType.SEQUENCE
表示使用數(shù)據(jù)庫(kù)的序列號(hào)為新增加的實(shí)體對(duì)象賦唯一值,作為實(shí)體的標(biāo)識(shí)。這種情況下需要數(shù)據(jù)庫(kù)提供對(duì)序列號(hào)的支持,常用的數(shù)據(jù)庫(kù)中,Oracle、PostgreSQL 等數(shù)據(jù)庫(kù)都能夠提供這種支持。
GenerationType.TABLE
表示使用數(shù)據(jù)庫(kù)中指定表的某個(gè)字段記錄實(shí)體對(duì)象的標(biāo)識(shí),通過該字段的增長(zhǎng)為新增加的實(shí)體對(duì)象賦唯一值,作為實(shí)體的標(biāo)識(shí)。
String generator
generator
屬性中定義實(shí)體標(biāo)識(shí)生成器的名稱。如果實(shí)體的標(biāo)識(shí)自動(dòng)生成策略不是 GenerationType.AUTO
或者 GenerationType.IDENTITY
,就需要提供相應(yīng)的 SequenceGenerator
或者 TableGenerator
注釋,然后將 generator
屬性值設(shè)置為注釋的 name
屬性值。
@javax.persistence.SequenceGenerator
如果實(shí)體標(biāo)識(shí)的自動(dòng)生策略是 GenerationType.SEQUENCE
,開發(fā)者需要為實(shí)體標(biāo)識(shí)字段提供 SequenceGenerator
注釋,它的參數(shù)描述了使用序列號(hào)生成實(shí)體標(biāo)識(shí)的具體細(xì)節(jié)。該注釋支持以下四個(gè)屬性:
表 1. SequenceGenerator 注釋屬性說明
屬性 |
說明 |
name |
該屬性是必須設(shè)置的屬性,它表示了 SequenceGenerator 注釋在 OpenJPA 容器中的唯一名稱,將會(huì)被 GeneratedValue 注釋的 generator 屬性使用。將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)的序列號(hào)特性時(shí),實(shí)體標(biāo)識(shí)字段的 GeneratedValue 注釋的 generator 屬性的值必須和某個(gè) SequenceGenerator 注釋的 name 屬性值保持一致。 |
sequenceName |
實(shí)體標(biāo)識(shí)所使用的數(shù)據(jù)庫(kù)序列號(hào)的名稱。該屬性是可選的,如果我們沒有為該屬性設(shè)置值,OpenJPA 框架將自動(dòng)創(chuàng)建名為 OPENJPA_SEQUENCE 的序列號(hào)。如果一個(gè) OpenJPA 容器中管理的多個(gè)實(shí)體都選擇使用序列號(hào)機(jī)制生成實(shí)體標(biāo)識(shí),而且實(shí)體類中都沒有指定標(biāo)識(shí)字段的 sequenceName 屬性,那么這些實(shí)體將會(huì)共享系統(tǒng)提供的默認(rèn)名為 OPENJPA_SEQUENCE 的序列號(hào)。這可能引起實(shí)體類編號(hào)的不連續(xù)。我們可以用下面的這個(gè)簡(jiǎn)單例子說明這種情況:假設(shè) OpenJPA 容器中存在兩個(gè)實(shí)體類 Dog 和 Fish,它們的實(shí)體標(biāo)識(shí)字段都是數(shù)值型,并且都選擇使用序列號(hào)生成實(shí)體標(biāo)識(shí),但是實(shí)體類中并沒有提供 sequenceName 屬性值。當(dāng)我們首先持久化一個(gè) Dog 對(duì)象時(shí),它的實(shí)體標(biāo)識(shí)將會(huì)是 1,緊接著我們持久化一個(gè) Fish 對(duì)象,它的實(shí)體標(biāo)識(shí)就是 2,依次類推。 |
initialValue |
該屬性設(shè)置所使用序列號(hào)的起始值。 |
allocationSize |
一些數(shù)據(jù)庫(kù)的序列化機(jī)制允許預(yù)先分配序列號(hào),比如 Oracle,這種預(yù)先分配機(jī)制可以一次性生成多個(gè)序列號(hào),然后放在 cache 中,數(shù)據(jù)庫(kù)用戶獲取的序列號(hào)是從序列號(hào) cache 中獲取的,這樣就避免了在每一次數(shù)據(jù)庫(kù)用戶獲取序列號(hào)的時(shí)候都要重新生成序列號(hào)。allocationSize 屬性設(shè)置的就是一次預(yù)先分配序列號(hào)的數(shù)目,默認(rèn)情況下 allocationSize 屬性的值是 50。 |
@javax.persistence.TableGenerator
如果實(shí)體標(biāo)識(shí)的自動(dòng)生策略是 GenerationType.TABLE,開發(fā)者需要為實(shí)體標(biāo)識(shí)字段提供 TableGenerator 注釋,它的參數(shù)描述了使用數(shù)據(jù)庫(kù)表生成實(shí)體標(biāo)識(shí)的具體細(xì)節(jié)。該注釋支持下列屬性:
表 2. TableGenerator 注釋屬性說明
屬性 |
說明 |
name |
該屬性是必須設(shè)置的屬性,它表示了 TableGenerator 注釋在 OpenJPA 容器中的唯一名稱,將會(huì)被 GeneratedValue 注釋的 generator 屬性所使用。將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)表時(shí),實(shí)體標(biāo)識(shí)字段的 GeneratedValue 注釋的 generator 屬性的值必須和某個(gè) TableGenerator 注釋的 name 屬性值保持一致。 |
table |
該屬性設(shè)置的是生成序列號(hào)的表的名稱。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)的表名 OPENJPA_SEQUENCES_TABLE 。 |
schema |
該屬性設(shè)置的是生成序列號(hào)的表的 schema。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)默認(rèn)使用當(dāng)前數(shù)據(jù)庫(kù)用戶對(duì)應(yīng)的 schema。 |
catalog |
該屬性設(shè)置的是生成序列號(hào)的表的 catalog。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)當(dāng)前數(shù)據(jù)庫(kù)用戶對(duì)應(yīng)的 catalog。 |
pkColumnName |
該屬性設(shè)置的是生成序列號(hào)的表中的主鍵字段的名稱,該字段將保存代表每個(gè)實(shí)體對(duì)應(yīng)的標(biāo)識(shí)值對(duì)應(yīng)的特征字符串。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)值 ID 。 |
valueColumnName |
該屬性設(shè)置的是生成序列號(hào)的表中記錄實(shí)體對(duì)應(yīng)標(biāo)識(shí)最大值的字段的名稱。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該 屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)值 SEQUENCE_VALUE 。 |
pkColumnValue |
該屬性設(shè)置的是生成序列號(hào)的表中的主鍵字段的特征字符串值 ( 比如 customID ),該字段將保存代表每個(gè)實(shí)體對(duì)應(yīng)的標(biāo)識(shí)值對(duì)應(yīng)的特征字符串。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)值 DEFAULT 。可以為多個(gè)實(shí)體設(shè)置相同的 pkColumnValue 屬性值,這些實(shí)體標(biāo)識(shí)的生成將通過同一列的值的遞增來實(shí)現(xiàn)。 |
initialValue |
該屬性設(shè)置的是生成序列號(hào)的表實(shí)體標(biāo)識(shí)的初始值。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)值 0 。 |
allocationSize |
為了降低標(biāo)識(shí)生成時(shí)頻繁操作數(shù)據(jù)庫(kù)造成 的性能上的影響,實(shí)體標(biāo)識(shí)生成的時(shí)候會(huì)一次性的獲取多個(gè)實(shí)體標(biāo)識(shí),該屬性設(shè)置的就是一次性獲取實(shí)體標(biāo)識(shí)的數(shù)目。該屬性并不是必須設(shè)置的屬性,如果開發(fā)者沒有為該屬性設(shè)置值,OpenJPA 容器將會(huì)使用默認(rèn)值 50 。 |
回頁(yè)首
實(shí)體標(biāo)識(shí)自動(dòng)生成
在上面的小節(jié)中,我們了解了和實(shí)體標(biāo)識(shí)自動(dòng)生成相關(guān)的注釋,接下來我們將結(jié)合一個(gè)簡(jiǎn)單的例子講述如何分別使用這些實(shí)體標(biāo)識(shí)自動(dòng)生成策略實(shí)現(xiàn)實(shí)體標(biāo)識(shí)的自動(dòng)生成。
我們首先假設(shè)有一個(gè) Animal
實(shí)體需要被持久化,它包括 ID
和 NAME
屬性,其中 ID
是它的主鍵字段。Animal
實(shí)體的標(biāo)識(shí)需要自動(dòng)生成,我們將分析在這四種不用的情況下,如何使用 OpenJPA 提供的注釋,結(jié)合具體數(shù)據(jù)庫(kù)支持的特性,如自增長(zhǎng)字段、序列號(hào)等來實(shí)現(xiàn)實(shí)體標(biāo)識(shí)的自動(dòng)生成。
容器自動(dòng)生成
OpenJPA 容器默認(rèn)的實(shí)體標(biāo)識(shí)自動(dòng)生成策略是由容器管理實(shí)體標(biāo)識(shí)的自動(dòng)生成,容器管理的實(shí)體標(biāo)識(shí)可以支持?jǐn)?shù)值型和字符型兩種。當(dāng)容器管理的實(shí)體標(biāo)識(shí)是數(shù)字型時(shí),OpenJPA 容器自動(dòng)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)表 OPENJPA_SEQUENCE_TABLE
,用其中的 SEQUENCE_VALUE
字段來記錄實(shí)體的實(shí)體標(biāo)識(shí)的增長(zhǎng)。
當(dāng)容器管理的實(shí)體標(biāo)識(shí)是字符串類型時(shí),OpenJPA 支持使用 uuid-string 和 uuid-hex 兩種方式生成相應(yīng)的實(shí)體標(biāo)識(shí)。如果我們選擇使用 uuid-string 方式生成實(shí)體標(biāo)識(shí)時(shí),OpenJPA 框架會(huì)自動(dòng)為實(shí)體生成一個(gè) 128 位的 UUID,并且將這個(gè) UUID 轉(zhuǎn)化為使用 16 位字符表示的字符串。如果我們選擇使用 uuid-hex 方式生成實(shí)體標(biāo)識(shí)時(shí),OpenJPA 框架會(huì)自動(dòng)為實(shí)體生成一個(gè) 128 位的 UUID,并且將這個(gè) UUID 轉(zhuǎn)化為使用 32 位字符表示的 16 進(jìn)制的字符串。
數(shù)值標(biāo)識(shí)
容器管理的實(shí)體標(biāo)識(shí)可以是數(shù)值型的,OpenJPA 框架管理的實(shí)體標(biāo)識(shí)借助于數(shù)據(jù)庫(kù)的表來實(shí)現(xiàn),在運(yùn)行時(shí) OpenJPA 框架會(huì)自動(dòng)在數(shù)據(jù)庫(kù)中創(chuàng)建表 OPENJPA_SEQUENCE_TABLE
。它有兩個(gè)字段:ID
和 SEQUENCE_VALUE
,這兩個(gè)字段都是數(shù)值類型,其中 ID
是表的主鍵字段,它的內(nèi)容是查詢當(dāng)前實(shí)體標(biāo)識(shí)時(shí)所使用的關(guān)鍵詞,默認(rèn)值是 0。而 SEQUENCE_VALUE
記錄了當(dāng)前 OpenJPA 框架中當(dāng)前實(shí)體標(biāo)識(shí)的歷史數(shù)據(jù),內(nèi)容是已經(jīng)被獲取實(shí)體標(biāo)識(shí)的最大數(shù)值加 1。
我們要使用注釋描述 Animal
實(shí)體的標(biāo)識(shí)由容器自動(dòng)生成,只需要為它的標(biāo)識(shí)字段提供 GeneratedValue
注釋,并且把它的 strategy
屬性設(shè)置為 GenerationType.AUTO
, Animal
實(shí)體類的代碼片斷如下:
清單 1. 標(biāo)識(shí)由容器自動(dòng)生成的 Animal 實(shí)體類
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy=GenerationType.AUTO)
10. private long id;
11. private String name;
12.
13. …
14.
15. }
|
保存 Animal
實(shí)體的第一個(gè)實(shí)例時(shí),OpenJPA 框架自動(dòng)調(diào)用 SQL 語(yǔ)句 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID=0
,從默認(rèn)保存實(shí)體標(biāo)識(shí)的 OPENJPA_SEQUENCE_TABLE
表中獲取實(shí)體的標(biāo)識(shí),如果不存在 ID
為 0 的記錄,OpenJPA 框架自動(dòng)將實(shí)體的標(biāo)識(shí)設(shè)置為 1。
容器管理實(shí)體標(biāo)識(shí)的情況下,為了獲得實(shí)體標(biāo)識(shí),應(yīng)用程序?qū)⒉坏貌活l繁地和數(shù)據(jù)庫(kù)交互,這會(huì)影響應(yīng)用程序的運(yùn)行效率。OpenJPA 中使用實(shí)體標(biāo)識(shí)緩存機(jī)制解決這個(gè)問題。默認(rèn)情況下,當(dāng)應(yīng)用程序第一次獲取實(shí)體標(biāo)識(shí)時(shí),OpenJPA 框架從數(shù)據(jù)庫(kù)中一次性獲取 50 個(gè)連續(xù)的實(shí)體標(biāo)識(shí)緩存起來,當(dāng)下一次應(yīng)用程序需要獲取實(shí)體標(biāo)識(shí)時(shí),OpenJPA 將首先檢測(cè)緩存中是否存在實(shí)體標(biāo)識(shí),如果存在,OpenJPA 將直接使用緩存中的實(shí)體標(biāo)識(shí),如果不存在,OpenJPA 框架將會(huì)從數(shù)據(jù)庫(kù)中再次獲取 50 個(gè)連續(xù)的實(shí)體標(biāo)識(shí)緩存起來,如此類推。這樣的處理方式可以大大減少由于獲取實(shí)體標(biāo)識(shí)而產(chǎn)生的數(shù)據(jù)庫(kù)交互,提升應(yīng)用程序的運(yùn)行效率。
當(dāng)實(shí)體標(biāo)識(shí)成功獲取之后,OpenJPA 框架會(huì)把當(dāng)前實(shí)體標(biāo)識(shí)的最大值 +1 后持久化到數(shù)據(jù)庫(kù)中。由于實(shí)體標(biāo)識(shí)緩存的原因,當(dāng)我們第一次獲取實(shí)體標(biāo)識(shí)后,OpenJPA 會(huì)將 OPENJPA_SEQUENCE_TABLE
表的 SEQUENCE_VALUE
的值設(shè)置為 51,當(dāng) OpenJPA 多次從數(shù)據(jù)庫(kù)中獲取實(shí)體標(biāo)識(shí)后,SEQUENCE_VALUE
的值會(huì)以 50 為單位遞增,變?yōu)?101、151、201 …。
OpenJPA 緩存的實(shí)體標(biāo)識(shí)不是永久存在的,只能在同一個(gè) EntityManagerFactory
管理范圍內(nèi)起作用,也就是說,當(dāng)獲取實(shí)體標(biāo)識(shí)的 EntityManagerFactory
對(duì)象被關(guān)閉后,這些被獲取的實(shí)體標(biāo)識(shí)中沒有用掉的那一部分標(biāo)識(shí)就丟失了,這會(huì)造成實(shí)體標(biāo)識(shí)的不連續(xù)。由同一個(gè) EntityManagerFactory
對(duì)象創(chuàng)建的 EntityManager
上下文之間則能夠共享 OpenJPA 框架獲取的實(shí)體標(biāo)識(shí),這意味著,我們可以使用同一個(gè) EntityManagerFactory
對(duì)象創(chuàng)建多個(gè) EntityManager
對(duì)象,用它來持久化實(shí)體,然后關(guān)閉它,在持久化過程中所需要的實(shí)體表示將會(huì)使用同一個(gè)實(shí)體標(biāo)識(shí)的緩存區(qū),因此不會(huì)引起實(shí)體標(biāo)識(shí)的丟失。
容器管理的實(shí)體標(biāo)識(shí)還有一個(gè)非常重要的特性:所有被容器管理的實(shí)體標(biāo)識(shí)都是共享的。不管 OpenJPA 容器中存在多少個(gè)不同的被容器管理的實(shí)體標(biāo)識(shí),它們都會(huì)從同一個(gè)實(shí)體標(biāo)識(shí)緩存中獲取實(shí)體標(biāo)識(shí)。我們可以用下面的例子說明這種情況:假設(shè) OpenJPA 容器中存在兩個(gè)實(shí)體類 Dog
和 Fish
,它們的實(shí)體標(biāo)識(shí)字段都是數(shù)值型,并且都由 OpenJPA 管理。當(dāng)我們首先持久化一個(gè) Dog
對(duì)象時(shí),它的實(shí)體標(biāo)識(shí)將會(huì)是 1,緊接著我們持久化一個(gè) Fish
對(duì)象,它的實(shí)體標(biāo)識(shí)就是 2,依次類推。
uuid-string
要使用 uuid-string 機(jī)制自動(dòng)生成實(shí)體標(biāo)識(shí),我們需要將實(shí)體主鍵字段的 GeneratedValue
注釋的 strategy
屬性設(shè)置為 GenarationType.AUTO
,然后將 GeneratedValue
注釋的 generator
屬性設(shè)置為 uuid-string
。以 Animal 實(shí)體類為例,我們只需要將 Animal 實(shí)體修改為如下內(nèi)容:
清單 2. 使用 uuid-string 機(jī)制自動(dòng)生成實(shí)體標(biāo)識(shí)
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy=GenerationType.AUTO, generator = "uuid-string")
10. private String id;
11. private String name;
12.
13. …
14.
15. }
|
uuid-hex
要使用 uuid-hex 機(jī)制自動(dòng)生成實(shí)體標(biāo)識(shí),我們必須將實(shí)體主鍵字段的 GeneratedValue
注釋的 strategy
屬性設(shè)置為 GenarationType.AUTO
,然后將 GeneratedValue
注釋的 generator
屬性設(shè)置為 uuid-hex
。以 Animal 實(shí)體類為例,我們只需要將 Animal 實(shí)體修改為如下內(nèi)容:
清單 3. 使用 uuid-hex 機(jī)制自動(dòng)生成實(shí)體標(biāo)識(shí)
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy=GenerationType.AUTO, generator = "uuid-hex")
10. private String id;
11. private String name;
12.
13. …
14.
15. }
|
自增長(zhǎng)字段
自增長(zhǎng)字段是 HSQL、SQL Server、MySQL、DB2、Derby 等數(shù)據(jù)庫(kù)提供的一種特性,用于為數(shù)據(jù)庫(kù)的記錄提供自動(dòng)增長(zhǎng)的編號(hào),應(yīng)用程序的設(shè)計(jì)者通常期望將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)的這種特性,OpenJPA 框架中的實(shí)體標(biāo)識(shí)能夠滿足應(yīng)用程序設(shè)計(jì)者的要求,使用數(shù)據(jù)庫(kù)的自增長(zhǎng)字段為實(shí)體自動(dòng)生成標(biāo)識(shí)。
要將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)的自增長(zhǎng)字段特性,需要數(shù)據(jù)庫(kù)和實(shí)體定義的雙方配合才能夠達(dá)到:首先,必須將實(shí)體標(biāo)識(shí)字段對(duì)應(yīng)的數(shù)據(jù)庫(kù)列修改為自動(dòng)增長(zhǎng)列,另外還需要將實(shí)體類中實(shí)體標(biāo)識(shí)字段的 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.IDENTITY
。
我們以 Animal 實(shí)體在 HSQL 數(shù)據(jù)庫(kù)中的持久化來說明如何使用自增長(zhǎng)字段自動(dòng)生成實(shí)體標(biāo)識(shí)所需要采取的步驟:
首先,我們使用下面的 SQL 語(yǔ)句創(chuàng)建 Animal 表,把它的 ID
字段設(shè)置為自動(dòng)增長(zhǎng)類型:
清單 4. 將 ID 字段設(shè)置為自動(dòng)增長(zhǎng)類型的 SQL 語(yǔ)句
CREATE TEXT TABLE ANIMAL (
ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
NAME VARCHAR(255) NOT NULL
)
|
在數(shù)據(jù)庫(kù)部分將表的主鍵字段設(shè)置為自動(dòng)增長(zhǎng)字段后,在實(shí)體 Animal
的定義中,我們需要將 id
字段 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.IDENTITY
。Animal 實(shí)體類修改后的代碼片段如下。
清單 5. 標(biāo)識(shí)由自增長(zhǎng)字段生成的 Animal 實(shí)體類
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy=GenerationType.IDENTITY)
10. private long id;
11. private String name;
12.
13. …
14.
15. }
|
序列號(hào)(Sequence)
序列號(hào)是 Oracle、PostgreSQL 等數(shù)據(jù)庫(kù)提供的一種特性,用于為數(shù)據(jù)庫(kù)的記錄提供自動(dòng)增長(zhǎng)的編號(hào),使用 Oracle、PostgreSQL 等數(shù)據(jù)庫(kù)應(yīng)用程序的設(shè)計(jì)者通常期望將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)的這種特性,OpenJPA 框架中的實(shí)體標(biāo)識(shí)能夠滿足應(yīng)用程序設(shè)計(jì)者的要求,使用數(shù)據(jù)庫(kù)的序列號(hào)為實(shí)體自動(dòng)生成標(biāo)識(shí)。
要將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)的序列號(hào)特性,需要數(shù)據(jù)庫(kù)和實(shí)體定義的雙方配合才能夠達(dá)到:首先,必須在數(shù)據(jù)庫(kù)中創(chuàng)建合適的序列號(hào),另外還需要為實(shí)體標(biāo)識(shí)字段提供 SequenceGenerator
注釋,設(shè)置它的參數(shù),為實(shí)體類提供關(guān)于序列號(hào)的信息,同時(shí)將實(shí)體類中實(shí)體標(biāo)識(shí)字段的 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.SEQUENCE
,將 generator
屬性的值設(shè)置為 SequenceGenerator
注釋的 name
屬性的值。
我們以 Animal 實(shí)體在 Oracle 數(shù)據(jù)庫(kù)中的持久化來說明如何使用自增長(zhǎng)字段自動(dòng)生成實(shí)體標(biāo)識(shí)所需要采取的步驟:
首先,在 Oracle 數(shù)據(jù)庫(kù)中運(yùn)行下面的 SQL 語(yǔ)句創(chuàng)建名為 HelloWorldSequence
的序列號(hào),序列號(hào)支持 cache,大小為 50:
清單 6. 創(chuàng)建序列號(hào)的 SQL 語(yǔ)句
CREATE SEQUENCE HELLOWORLDSEQUENCE
START WITH 0
INCREMENT BY 1
MINVALUE 1
CACHE 50
NOCYCLE
NOORDER
|
然后,在 Oracle 數(shù)據(jù)庫(kù)中,我們使用下面的 SQL 語(yǔ)句創(chuàng)建 ANIMAL
表:
清單 7. 創(chuàng)建 ANIMAL 表
CREATE TABLE EOS52.ANIMAL
(
ID CHAR(10),
NAME VARCHAR2(100) NOT NULL,
CONSTRAINT PK_ANIMAL PRIMARY KEY (ID )
)
|
在數(shù)據(jù)庫(kù)部分創(chuàng)建合適的序列號(hào)和相應(yīng)的數(shù)據(jù)庫(kù)表后,在實(shí)體 Animal
的定義中,我們需要將 id
字段 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.SEQUENCE
,設(shè)置它的 generator
屬性的值為 SeqGenerator
。我們還需要為 id
字段提供另外一個(gè)相關(guān)的注釋 SequenceGenerator
,設(shè)置它的 name
屬性為 SeqGenerator
,設(shè)置它 sequenceName
屬性為 HelloWorldSequence
。Animal 實(shí)體類修改后的代碼片段如下。
清單 8. 標(biāo)識(shí)由序列號(hào)生成的 Animal 實(shí)體類
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "SeqGenerator")
10. @SequenceGenerator(name = "SeqGenerator",
sequenceName = " HelloWorldSequence")
11. private long id;
12. private String name;
13.
14. …
15.
16. }
|
數(shù)據(jù)庫(kù)表
除了使用容器生成的實(shí)體標(biāo)識(shí),或者借助于數(shù)據(jù)庫(kù)的自增長(zhǎng)字段或者序列號(hào)等方式生成實(shí)體標(biāo)識(shí)之外,我們還可以選擇借助數(shù)據(jù)庫(kù)表來自動(dòng)生成實(shí)體標(biāo)識(shí)。原理是我們提供一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)表,該表的主鍵列 ( 假設(shè)列名 ID
) 記錄實(shí)體編號(hào)的特征字符串 ( 假設(shè)存在一條記錄的 ID
為 customID
),另外一列 ( 假設(shè)列名為 SEQUENCE_VALUE
) 記錄該特征字符串對(duì)應(yīng)實(shí)體標(biāo)識(shí)的最大值。編寫實(shí)體代碼時(shí),我們指定實(shí)體標(biāo)識(shí)由數(shù)據(jù)庫(kù)表中指定的特征字符串 ( 如 customID
) 對(duì)應(yīng)的列 SEQUENCE_VALUE
處理,當(dāng)有新的實(shí)體被持久化時(shí),容器將獲取行 customID
、列 SEQUENCE_VALUE
對(duì)應(yīng)的數(shù)值 +1 后作為新實(shí)體的標(biāo)識(shí),同時(shí)將該列的值也自動(dòng) +1。
要將實(shí)體標(biāo)識(shí)的自動(dòng)生成委托給數(shù)據(jù)庫(kù)表,需要數(shù)據(jù)庫(kù)和實(shí)體定義的雙方配合才能夠達(dá)到:首先,必須在數(shù)據(jù)庫(kù)中創(chuàng)建合適的保存實(shí)體標(biāo)識(shí)的表,另外還需要為實(shí)體標(biāo)識(shí)字段提供 TableGenerator
注釋,設(shè)置它的參數(shù),為實(shí)體類提供關(guān)于數(shù)據(jù)庫(kù)表、字段的信息,同時(shí)將實(shí)體類中實(shí)體標(biāo)識(shí)字段的 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.Table
,將 generator
屬性的值設(shè)置為 SequenceGenerator
注釋的 name
屬性的值。
我們以 Animal 實(shí)體類來說明使用數(shù)據(jù)庫(kù)表自動(dòng)生成實(shí)體標(biāo)識(shí)所需要采取的步驟:我們假設(shè)存在這樣的場(chǎng)景,Animal 實(shí)體的標(biāo)識(shí)由應(yīng)用程序中自定義的數(shù)據(jù)庫(kù)表 MY_KEYS
自動(dòng)生成,MY_KEYS
表中有兩列,一列是 KEYID
,它保存實(shí)體標(biāo)識(shí)的特征值,一列是 KEYVALUE
,它保存實(shí)體當(dāng)前的最大編號(hào),除此之外,我們還決定使用 ANIMALID
作為 Animal 實(shí)體標(biāo)識(shí)的特征字符串。
首先,在數(shù)據(jù)庫(kù)中使用下面的 SQL 語(yǔ)句創(chuàng)建名為 MY_KEYS
的數(shù)據(jù)庫(kù)表。在 OpenJPA 容器中,如果我們沒有創(chuàng)建 MY_KEYS
表,OpenJPA 容器將幫我們自動(dòng)生成對(duì)應(yīng)的表結(jié)構(gòu)。
清單 9. 創(chuàng)建數(shù)據(jù)庫(kù)表 MY_KEYS
CREATE TABLE MY_KEYS (
KEYID VARCHAR(255) NOT NULL,
KEYVALUE BIGINT,
PRIMARY KEY (KEYID)
)
|
在數(shù)據(jù)庫(kù)部分創(chuàng)建合適的數(shù)據(jù)庫(kù)表后,在實(shí)體 Animal 的定義中,我們需要將 id
字段 GeneratedValue
注釋的 stragety
屬性的值設(shè)置為 GenerationType.TABLE
,設(shè)置它的 generator
屬性的值為 TableGenerator
。我們還需要為 id
字段提供另外一個(gè)注釋 TableGenerator
,設(shè)置它的 name
屬性為 TableGenerator
,設(shè)置它的 table
屬性為 MYKEYS
、pkColumnName
屬性為 KEYID
、valueColumnName
屬性為 KEYVALUE
、 ANIMALID
屬性為 ANIMALID
。Animal 實(shí)體類修改后的代碼片段如下。
清單 10. 標(biāo)識(shí)由數(shù)據(jù)庫(kù)表生成的 Animal 實(shí)體類
1. import javax.persistence.Entity;
2. import javax.persistence.GeneratedValue;
3. import javax.persistence.GenerationType;
4. import javax.persistence.Id;
5.
6. @Entity
7. public class Animal {
8. @Id
9. @GeneratedValue(strategy = GenerationType.TABLE,
generator = " TableGenerator ")
10. @TableGenerator(name = " TableGenerator", table = "MY_KEYS",
pkColumnName = "KEYID", valueColumnName = "KEYVALUE",
pkColumnValue = "ANIMALID")
11. private long id;
12. private String name;
13.
14. …
15.
16. }
|
回頁(yè)首
調(diào)用代碼
上面的章節(jié)中我們學(xué)習(xí)了分別使用四種方式來自動(dòng)生成實(shí)體的標(biāo)識(shí),由于這四種情況下,Animal 實(shí)體的標(biāo)識(shí)都由 OpenJPA 和數(shù)據(jù)庫(kù)協(xié)作后自動(dòng)生成,對(duì)于開發(fā)者而言,這個(gè)過程是透明的,因此我們可以使用相同的方式來創(chuàng)建這些實(shí)體:創(chuàng)建新的 Animal 實(shí)例的時(shí)候不再需要為主鍵字段提供屬性值,只需要設(shè)置 Animal 實(shí)例的非標(biāo)識(shí)字段 name
的值即可。下面的代碼演示了 Animal 實(shí)例的持久化代碼,請(qǐng)注意代碼中并沒有調(diào)用 Animal 實(shí)例的 setId 方法。
清單 11. Animal 實(shí)例的持久化代碼
1. EntityManagerFactory factory = Persistence.
2. createEntityManagerFactory(
3. "jpa-unit", System.getProperties());
4. EntityManager em = factory.createEntityManager();
5. em.getTransaction().begin();
6.
7. Animal animal = new Animal();
8. // 此處不需要調(diào)用 animal 的 setId 方法
9. animal.setName("ba guai!");
10. em.persist(animal);
11.
12. em.getTransaction().commit();
13. em.close();
14. em2.close();
15. factory.close();
|
回頁(yè)首
總結(jié)
本文介紹了開發(fā)者使用 OpenJPA 實(shí)現(xiàn)實(shí)體標(biāo)識(shí)自動(dòng)生成時(shí)可選擇使用的注釋,并且結(jié)合簡(jiǎn)單的例子,分別介紹了 OpenJPA 中實(shí)現(xiàn)容器管理的實(shí)體標(biāo)識(shí)自動(dòng)生成、結(jié)合數(shù)據(jù)庫(kù)自增長(zhǎng)字段、序列號(hào)、數(shù)據(jù)庫(kù)表等特性實(shí)現(xiàn)實(shí)體標(biāo)識(shí)自動(dòng)生成時(shí)注釋的具體用法和操作步驟。
http://www.ibm.com/developerworks/cn/java/j-lo-openjpa5/
posted on 2011-05-03 23:06
Alpha 閱讀(12995)
評(píng)論(0) 編輯 收藏 所屬分類:
MySQL NoSQL