- 浏览: 772187 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (208)
- Java (77)
- JavaScript (16)
- UML (1)
- Spring (24)
- Hibernate (11)
- J2EE部署 (18)
- 操作系统 (13)
- struts (11)
- jsp (3)
- J2EE (34)
- 数据库 (22)
- tomcat (4)
- apache (2)
- MyEclipse (13)
- Linux (14)
- Ext (6)
- Weblogic (2)
- 数据库 Oracle 空表导出 (1)
- Oracle (3)
- 编码 乱码 (1)
- 多线程 (5)
- jQuery (2)
- Apache Mina (1)
- ibatis (6)
- abator (1)
- svn (1)
- jvm (1)
- ERwin (2)
- mysql (2)
- ant (1)
- memcache (1)
- dubbo (1)
- PowerDesigner (1)
最新评论
-
di1984HIT:
Shallow heap & Retained heap -
tinguo002:
非常感谢 , 太棒了。
Spring注解方式,异常 'sessionFactory' or 'hibernateTemplate' is required的解决方法 -
白天看黑夜:
Apache Mina Server 2.0 中文参考手册(带 ...
Apache Mina – 简单的客户端/服务端应用示例 -
wumingxingzhe:
好文
Shallow heap & Retained heap -
di1984HIT:
学习了!!
工作流(Workflow)和BPM的不同
转自: http://www.ibm.com/developerworks/cn/java/j-lo-openjpa5/
数据的唯一性是所有应用程序非常基本的要求,由开发者或者用户来维护这种唯一性存在着较大的风险,因此,由系统自动产生唯一标识是一种常见的做法。OpenJPA 中支持四种不同的实体标识自动生成策略:
容器自动生成的实体标识;
使用数据库的自动增长字段生成实体标识;
根据数据库序列号(Sequence)技术生成实体标识;
使用数据库表的字段生成实体标识;
这四种方式各有优缺点,开发者可以根据实际情况进行选择。
可选择的注释
要让容器和数据库结合管理实体标识的自动生成,根据实际情况的不同,开发者可以选择 javax.persistence.*包下面的 GeneratedValue、SequenceGenerator、TableGenerator三个注释来描述实体的标识字段。
@javax.persistence.GeneratedValue
每一个需要自动生成实体标识的实体都需要为它的实体标识字段提供 GeneratedValue注释和相应的参数,OpenJPA 框架会根据注释和参数来处理实体标识的自动生成。
使用 GeneratedValue注释自动生成的实体标识可以是数值类型字段如 byte、short、int、long等,或者它们对应的包装器类型 Byte、Short、Integer、Long等,也可以是字符串类型。
GeneratedValue注释可以支持两个属性 strategy和 generator。
strategy
strategy是 GenerationType类型的枚举值,它的内容将指定 OpenJPA 容器自动生成实体标识的方式。strategy属性可以是下列枚举值:
GeneratorType.AUTO
表示实体标识由 OpenJPA 容器自动生成,这也是 Strategy 属性的默认值。
GenerationType.IDENTITY
OpenJPA 容器将使用数据库的自增长字段为新增加的实体对象赋唯一值,作为实体的标识。这种情况下需要数据库提供对自增长字段的支持,常用的数据库中,HSQL、SQL Server、MySQL、DB2、Derby 等数据库都能够提供这种支持。
GenerationType.SEQUENCE
表示使用数据库的序列号为新增加的实体对象赋唯一值,作为实体的标识。这种情况下需要数据库提供对序列号的支持,常用的数据库中,Oracle、PostgreSQL 等数据库都能够提供这种支持。
GenerationType.TABLE
表示使用数据库中指定表的某个字段记录实体对象的标识,通过该字段的增长为新增加的实体对象赋唯一值,作为实体的标识。
String generator
generator属性中定义实体标识生成器的名称。如果实体的标识自动生成策略不是 GenerationType.AUTO或者 GenerationType.IDENTITY,就需要提供相应的 SequenceGenerator或者 TableGenerator注释,然后将 generator属性值设置为注释的 name属性值。
@javax.persistence.SequenceGenerator
如果实体标识的自动生策略是 GenerationType.SEQUENCE,开发者需要为实体标识字段提供 SequenceGenerator注释,它的参数描述了使用序列号生成实体标识的具体细节。该注释支持以下四个属性:
表 1. SequenceGenerator 注释属性说明
@javax.persistence.TableGenerator
如果实体标识的自动生策略是 GenerationType.TABLE,开发者需要为实体标识字段提供 TableGenerator 注释,它的参数描述了使用数据库表生成实体标识的具体细节。该注释支持下列属性:
表 2. TableGenerator 注释属性说明
实体标识自动生成
在上面的小节中,我们了解了和实体标识自动生成相关的注释,接下来我们将结合一个简单的例子讲述如何分别使用这些实体标识自动生成策略实现实体标识的自动生成。
我们首先假设有一个 Animal实体需要被持久化,它包括 ID和 NAME属性,其中 ID是它的主键字段。Animal实体的标识需要自动生成,我们将分析在这四种不用的情况下,如何使用 OpenJPA 提供的注释,结合具体数据库支持的特性,如自增长字段、序列号等来实现实体标识的自动生成。
容器自动生成
OpenJPA 容器默认的实体标识自动生成策略是由容器管理实体标识的自动生成,容器管理的实体标识可以支持数值型和字符型两种。当容器管理的实体标识是数字型时,OpenJPA 容器自动创建一个数据库表 OPENJPA_SEQUENCE_TABLE,用其中的 SEQUENCE_VALUE字段来记录实体的实体标识的增长。
当容器管理的实体标识是字符串类型时,OpenJPA 支持使用 uuid-string 和 uuid-hex 两种方式生成相应的实体标识。如果我们选择使用 uuid-string 方式生成实体标识时,OpenJPA 框架会自动为实体生成一个 128 位的 UUID,并且将这个 UUID 转化为使用 16 位字符表示的字符串。如果我们选择使用 uuid-hex 方式生成实体标识时,OpenJPA 框架会自动为实体生成一个 128 位的 UUID,并且将这个 UUID 转化为使用 32 位字符表示的 16 进制的字符串。
数值标识
容器管理的实体标识可以是数值型的,OpenJPA 框架管理的实体标识借助于数据库的表来实现,在运行时 OpenJPA 框架会自动在数据库中创建表 OPENJPA_SEQUENCE_TABLE。它有两个字段:ID和 SEQUENCE_VALUE,这两个字段都是数值类型,其中 ID是表的主键字段,它的内容是查询当前实体标识时所使用的关键词,默认值是 0。而 SEQUENCE_VALUE记录了当前 OpenJPA 框架中当前实体标识的历史数据,内容是已经被获取实体标识的最大数值加 1。
我们要使用注释描述 Animal实体的标识由容器自动生成,只需要为它的标识字段提供 GeneratedValue注释,并且把它的 strategy属性设置为 GenerationType.AUTO, Animal实体类的代码片断如下:
清单 1. 标识由容器自动生成的 Animal 实体类
保存 Animal实体的第一个实例时,OpenJPA 框架自动调用 SQL 语句 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID=0,从默认保存实体标识的 OPENJPA_SEQUENCE_TABLE表中获取实体的标识,如果不存在 ID为 0 的记录,OpenJPA 框架自动将实体的标识设置为 1。
容器管理实体标识的情况下,为了获得实体标识,应用程序将不得不频繁地和数据库交互,这会影响应用程序的运行效率。OpenJPA 中使用实体标识缓存机制解决这个问题。默认情况下,当应用程序第一次获取实体标识时,OpenJPA 框架从数据库中一次性获取 50 个连续的实体标识缓存起来,当下一次应用程序需要获取实体标识时,OpenJPA 将首先检测缓存中是否存在实体标识,如果存在,OpenJPA 将直接使用缓存中的实体标识,如果不存在,OpenJPA 框架将会从数据库中再次获取 50 个连续的实体标识缓存起来,如此类推。这样的处理方式可以大大减少由于获取实体标识而产生的数据库交互,提升应用程序的运行效率。
当实体标识成功获取之后,OpenJPA 框架会把当前实体标识的最大值 +1 后持久化到数据库中。由于实体标识缓存的原因,当我们第一次获取实体标识后,OpenJPA 会将 OPENJPA_SEQUENCE_TABLE表的 SEQUENCE_VALUE的值设置为 51,当 OpenJPA 多次从数据库中获取实体标识后,SEQUENCE_VALUE的值会以 50 为单位递增,变为 101、151、201 …。
OpenJPA 缓存的实体标识不是永久存在的,只能在同一个 EntityManagerFactory管理范围内起作用,也就是说,当获取实体标识的 EntityManagerFactory对象被关闭后,这些被获取的实体标识中没有用掉的那一部分标识就丢失了,这会造成实体标识的不连续。由同一个 EntityManagerFactory对象创建的 EntityManager上下文之间则能够共享 OpenJPA 框架获取的实体标识,这意味着,我们可以使用同一个 EntityManagerFactory对象创建多个 EntityManager对象,用它来持久化实体,然后关闭它,在持久化过程中所需要的实体表示将会使用同一个实体标识的缓存区,因此不会引起实体标识的丢失。
容器管理的实体标识还有一个非常重要的特性:所有被容器管理的实体标识都是共享的。不管 OpenJPA 容器中存在多少个不同的被容器管理的实体标识,它们都会从同一个实体标识缓存中获取实体标识。我们可以用下面的例子说明这种情况:假设 OpenJPA 容器中存在两个实体类 Dog和 Fish,它们的实体标识字段都是数值型,并且都由 OpenJPA 管理。当我们首先持久化一个 Dog对象时,它的实体标识将会是 1,紧接着我们持久化一个 Fish对象,它的实体标识就是 2,依次类推。
uuid-string
要使用 uuid-string 机制自动生成实体标识,我们需要将实体主键字段的 GeneratedValue注释的 strategy属性设置为 GenarationType.AUTO,然后将 GeneratedValue注释的 generator属性设置为 uuid-string。以 Animal 实体类为例,我们只需要将 Animal 实体修改为如下内容:
清单 2. 使用 uuid-string 机制自动生成实体标识
uuid-hex
要使用 uuid-hex 机制自动生成实体标识,我们必须将实体主键字段的 GeneratedValue注释的 strategy属性设置为 GenarationType.AUTO,然后将 GeneratedValue注释的 generator属性设置为 uuid-hex。以 Animal 实体类为例,我们只需要将 Animal 实体修改为如下内容:
清单 3. 使用 uuid-hex 机制自动生成实体标识
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Animal {
@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator = "uuid-hex")
private String id;
private String name;
…
}
自增长字段
自增长字段是 HSQL、SQL Server、MySQL、DB2、Derby 等数据库提供的一种特性,用于为数据库的记录提供自动增长的编号,应用程序的设计者通常期望将实体标识的自动生成委托给数据库的这种特性,OpenJPA 框架中的实体标识能够满足应用程序设计者的要求,使用数据库的自增长字段为实体自动生成标识。
要将实体标识的自动生成委托给数据库的自增长字段特性,需要数据库和实体定义的双方配合才能够达到:首先,必须将实体标识字段对应的数据库列修改为自动增长列,另外还需要将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.IDENTITY。
我们以 Animal 实体在 HSQL 数据库中的持久化来说明如何使用自增长字段自动生成实体标识所需要采取的步骤:
首先,我们使用下面的 SQL 语句创建 Animal 表,把它的 ID字段设置为自动增长类型:
清单 4. 将 ID 字段设置为自动增长类型的 SQL 语句
在数据库部分将表的主键字段设置为自动增长字段后,在实体 Animal的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.IDENTITY。Animal 实体类修改后的代码片段如下。
清单 5. 标识由自增长字段生成的 Animal 实体类
序列号(Sequence)
序列号是 Oracle、PostgreSQL 等数据库提供的一种特性,用于为数据库的记录提供自动增长的编号,使用 Oracle、PostgreSQL 等数据库应用程序的设计者通常期望将实体标识的自动生成委托给数据库的这种特性,OpenJPA 框架中的实体标识能够满足应用程序设计者的要求,使用数据库的序列号为实体自动生成标识。
要将实体标识的自动生成委托给数据库的序列号特性,需要数据库和实体定义的双方配合才能够达到:首先,必须在数据库中创建合适的序列号,另外还需要为实体标识字段提供 SequenceGenerator注释,设置它的参数,为实体类提供关于序列号的信息,同时将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.SEQUENCE,将 generator属性的值设置为 SequenceGenerator注释的 name属性的值。
我们以 Animal 实体在 Oracle 数据库中的持久化来说明如何使用自增长字段自动生成实体标识所需要采取的步骤:
首先,在 Oracle 数据库中运行下面的 SQL 语句创建名为 HelloWorldSequence的序列号,序列号支持 cache,大小为 50:
清单 6. 创建序列号的 SQL 语句
然后,在 Oracle 数据库中,我们使用下面的 SQL 语句创建 ANIMAL表:
清单 7. 创建 ANIMAL 表
CREATE TABLE EOS52.ANIMAL
在数据库部分创建合适的序列号和相应的数据库表后,在实体 Animal的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.SEQUENCE,设置它的 generator属性的值为 SeqGenerator。我们还需要为 id字段提供另外一个相关的注释 SequenceGenerator,设置它的 name属性为 SeqGenerator,设置它 sequenceName属性为 HelloWorldSequence。Animal 实体类修改后的代码片段如下。
清单 8. 标识由序列号生成的 Animal 实体类
数据库表
除了使用容器生成的实体标识,或者借助于数据库的自增长字段或者序列号等方式生成实体标识之外,我们还可以选择借助数据库表来自动生成实体标识。原理是我们提供一个独立的数据库表,该表的主键列 ( 假设列名 ID) 记录实体编号的特征字符串 ( 假设存在一条记录的 ID为 customID),另外一列 ( 假设列名为 SEQUENCE_VALUE) 记录该特征字符串对应实体标识的最大值。编写实体代码时,我们指定实体标识由数据库表中指定的特征字符串 ( 如 customID) 对应的列 SEQUENCE_VALUE处理,当有新的实体被持久化时,容器将获取行 customID、列 SEQUENCE_VALUE对应的数值 +1 后作为新实体的标识,同时将该列的值也自动 +1。
要将实体标识的自动生成委托给数据库表,需要数据库和实体定义的双方配合才能够达到:首先,必须在数据库中创建合适的保存实体标识的表,另外还需要为实体标识字段提供 TableGenerator注释,设置它的参数,为实体类提供关于数据库表、字段的信息,同时将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.Table,将 generator属性的值设置为 SequenceGenerator注释的 name属性的值。
我们以 Animal 实体类来说明使用数据库表自动生成实体标识所需要采取的步骤:我们假设存在这样的场景,Animal 实体的标识由应用程序中自定义的数据库表 MY_KEYS自动生成,MY_KEYS表中有两列,一列是 KEYID,它保存实体标识的特征值,一列是 KEYVALUE,它保存实体当前的最大编号,除此之外,我们还决定使用 ANIMALID作为 Animal 实体标识的特征字符串。
首先,在数据库中使用下面的 SQL 语句创建名为 MY_KEYS的数据库表。在 OpenJPA 容器中,如果我们没有创建 MY_KEYS表,OpenJPA 容器将帮我们自动生成对应的表结构。
清单 9. 创建数据库表 MY_KEYS
在数据库部分创建合适的数据库表后,在实体 Animal 的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.TABLE,设置它的 generator属性的值为 TableGenerator。我们还需要为 id字段提供另外一个注释 TableGenerator,设置它的 name属性为 TableGenerator,设置它的 table属性为 MYKEYS、pkColumnName属性为 KEYID、valueColumnName属性为 KEYVALUE、 ANIMALID属性为 ANIMALID。Animal 实体类修改后的代码片段如下。
清单 10. 标识由数据库表生成的 Animal 实体类
调用代码
上面的章节中我们学习了分别使用四种方式来自动生成实体的标识,由于这四种情况下,Animal 实体的标识都由 OpenJPA 和数据库协作后自动生成,对于开发者而言,这个过程是透明的,因此我们可以使用相同的方式来创建这些实体:创建新的 Animal 实例的时候不再需要为主键字段提供属性值,只需要设置 Animal 实例的非标识字段 name的值即可。下面的代码演示了 Animal 实例的持久化代码,请注意代码中并没有调用 Animal 实例的 setId 方法。
清单 11. Animal 实例的持久化代码
总结
本文介绍了开发者使用 OpenJPA 实现实体标识自动生成时可选择使用的注释,并且结合简单的例子,分别介绍了 OpenJPA 中实现容器管理的实体标识自动生成、结合数据库自增长字段、序列号、数据库表等特性实现实体标识自动生成时注释的具体用法和操作步骤。
数据的唯一性是所有应用程序非常基本的要求,由开发者或者用户来维护这种唯一性存在着较大的风险,因此,由系统自动产生唯一标识是一种常见的做法。OpenJPA 中支持四种不同的实体标识自动生成策略:
容器自动生成的实体标识;
使用数据库的自动增长字段生成实体标识;
根据数据库序列号(Sequence)技术生成实体标识;
使用数据库表的字段生成实体标识;
这四种方式各有优缺点,开发者可以根据实际情况进行选择。
可选择的注释
要让容器和数据库结合管理实体标识的自动生成,根据实际情况的不同,开发者可以选择 javax.persistence.*包下面的 GeneratedValue、SequenceGenerator、TableGenerator三个注释来描述实体的标识字段。
@javax.persistence.GeneratedValue
每一个需要自动生成实体标识的实体都需要为它的实体标识字段提供 GeneratedValue注释和相应的参数,OpenJPA 框架会根据注释和参数来处理实体标识的自动生成。
使用 GeneratedValue注释自动生成的实体标识可以是数值类型字段如 byte、short、int、long等,或者它们对应的包装器类型 Byte、Short、Integer、Long等,也可以是字符串类型。
GeneratedValue注释可以支持两个属性 strategy和 generator。
strategy
strategy是 GenerationType类型的枚举值,它的内容将指定 OpenJPA 容器自动生成实体标识的方式。strategy属性可以是下列枚举值:
GeneratorType.AUTO
表示实体标识由 OpenJPA 容器自动生成,这也是 Strategy 属性的默认值。
GenerationType.IDENTITY
OpenJPA 容器将使用数据库的自增长字段为新增加的实体对象赋唯一值,作为实体的标识。这种情况下需要数据库提供对自增长字段的支持,常用的数据库中,HSQL、SQL Server、MySQL、DB2、Derby 等数据库都能够提供这种支持。
GenerationType.SEQUENCE
表示使用数据库的序列号为新增加的实体对象赋唯一值,作为实体的标识。这种情况下需要数据库提供对序列号的支持,常用的数据库中,Oracle、PostgreSQL 等数据库都能够提供这种支持。
GenerationType.TABLE
表示使用数据库中指定表的某个字段记录实体对象的标识,通过该字段的增长为新增加的实体对象赋唯一值,作为实体的标识。
String generator
generator属性中定义实体标识生成器的名称。如果实体的标识自动生成策略不是 GenerationType.AUTO或者 GenerationType.IDENTITY,就需要提供相应的 SequenceGenerator或者 TableGenerator注释,然后将 generator属性值设置为注释的 name属性值。
@javax.persistence.SequenceGenerator
如果实体标识的自动生策略是 GenerationType.SEQUENCE,开发者需要为实体标识字段提供 SequenceGenerator注释,它的参数描述了使用序列号生成实体标识的具体细节。该注释支持以下四个属性:
表 1. SequenceGenerator 注释属性说明
属性 | 说明 |
name | 该属性是必须设置的属性,它表示了 SequenceGenerator注释在 OpenJPA 容器中的唯一名称,将会被 GeneratedValue注释的 generator属性使用。将实体标识的自动生成委托给数据库的序列号特性时,实体标识字段的 GeneratedValue注释的 generator属性的值必须和某个 SequenceGenerator注释的 name属性值保持一致。 |
sequenceName | 实体标识所使用的数据库序列号的名称。该属性是可选的,如果我们没有为该属性设置值,OpenJPA 框架将自动创建名为 OPENJPA_SEQUENCE的序列号。如果一个 OpenJPA 容器中管理的多个实体都选择使用序列号机制生成实体标识,而且实体类中都没有指定标识字段的 sequenceName属性,那么这些实体将会共享系统提供的默认名为 OPENJPA_SEQUENCE的序列号。这可能引起实体类编号的不连续。我们可以用下面的这个简单例子说明这种情况:假设 OpenJPA 容器中存在两个实体类 Dog 和 Fish,它们的实体标识字段都是数值型,并且都选择使用序列号生成实体标识,但是实体类中并没有提供 sequenceName属性值。当我们首先持久化一个 Dog 对象时,它的实体标识将会是 1,紧接着我们持久化一个 Fish 对象,它的实体标识就是 2,依次类推。 |
initialValue | 该属性设置所使用序列号的起始值。 |
allocationSize | 一些数据库的序列化机制允许预先分配序列号,比如 Oracle,这种预先分配机制可以一次性生成多个序列号,然后放在 cache 中,数据库用户获取的序列号是从序列号 cache 中获取的,这样就避免了在每一次数据库用户获取序列号的时候都要重新生成序列号。allocationSize属性设置的就是一次预先分配序列号的数目,默认情况下 allocationSize属性的值是 50。 |
@javax.persistence.TableGenerator
如果实体标识的自动生策略是 GenerationType.TABLE,开发者需要为实体标识字段提供 TableGenerator 注释,它的参数描述了使用数据库表生成实体标识的具体细节。该注释支持下列属性:
表 2. TableGenerator 注释属性说明
属性 | 说明 |
name | 该属性是必须设置的属性,它表示了 TableGenerator注释在 OpenJPA 容器中的唯一名称,将会被 GeneratedValue注释的 generator属性所使用。将实体标识的自动生成委托给数据库表时,实体标识字段的 GeneratedValue注释的 generator属性的值必须和某个 TableGenerator注释的 name属性值保持一致。 |
table | 该属性设置的是生成序列号的表的名称。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认的表名 OPENJPA_SEQUENCES_TABLE。 |
schema | 该属性设置的是生成序列号的表的 schema。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会默认使用当前数据库用户对应的 schema。 |
catalog | 该属性设置的是生成序列号的表的 catalog。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认当前数据库用户对应的 catalog。 |
pkColumnName | 该属性设置的是生成序列号的表中的主键字段的名称,该字段将保存代表每个实体对应的标识值对应的特征字符串。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认值 ID。 |
valueColumnName | 该属性设置的是生成序列号的表中记录实体对应标识最大值的字段的名称。该属性并不是必须设置的属性,如果开发者没有为该 属性设置值,OpenJPA 容器将会使用默认值 SEQUENCE_VALUE。 |
pkColumnValue | 该属性设置的是生成序列号的表中的主键字段的特征字符串值 ( 比如 customID ),该字段将保存代表每个实体对应的标识值对应的特征字符串。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认值 DEFAULT。可以为多个实体设置相同的 pkColumnValue属性值,这些实体标识的生成将通过同一列的值的递增来实现。 |
initialValue | 该属性设置的是生成序列号的表实体标识的初始值。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认值 0 。 |
allocationSize | 为了降低标识生成时频繁操作数据库造成 的性能上的影响,实体标识生成的时候会一次性的获取多个实体标识,该属性设置的就是一次性获取实体标识的数目。该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认值 50 。 |
实体标识自动生成
在上面的小节中,我们了解了和实体标识自动生成相关的注释,接下来我们将结合一个简单的例子讲述如何分别使用这些实体标识自动生成策略实现实体标识的自动生成。
我们首先假设有一个 Animal实体需要被持久化,它包括 ID和 NAME属性,其中 ID是它的主键字段。Animal实体的标识需要自动生成,我们将分析在这四种不用的情况下,如何使用 OpenJPA 提供的注释,结合具体数据库支持的特性,如自增长字段、序列号等来实现实体标识的自动生成。
容器自动生成
OpenJPA 容器默认的实体标识自动生成策略是由容器管理实体标识的自动生成,容器管理的实体标识可以支持数值型和字符型两种。当容器管理的实体标识是数字型时,OpenJPA 容器自动创建一个数据库表 OPENJPA_SEQUENCE_TABLE,用其中的 SEQUENCE_VALUE字段来记录实体的实体标识的增长。
当容器管理的实体标识是字符串类型时,OpenJPA 支持使用 uuid-string 和 uuid-hex 两种方式生成相应的实体标识。如果我们选择使用 uuid-string 方式生成实体标识时,OpenJPA 框架会自动为实体生成一个 128 位的 UUID,并且将这个 UUID 转化为使用 16 位字符表示的字符串。如果我们选择使用 uuid-hex 方式生成实体标识时,OpenJPA 框架会自动为实体生成一个 128 位的 UUID,并且将这个 UUID 转化为使用 32 位字符表示的 16 进制的字符串。
数值标识
容器管理的实体标识可以是数值型的,OpenJPA 框架管理的实体标识借助于数据库的表来实现,在运行时 OpenJPA 框架会自动在数据库中创建表 OPENJPA_SEQUENCE_TABLE。它有两个字段:ID和 SEQUENCE_VALUE,这两个字段都是数值类型,其中 ID是表的主键字段,它的内容是查询当前实体标识时所使用的关键词,默认值是 0。而 SEQUENCE_VALUE记录了当前 OpenJPA 框架中当前实体标识的历史数据,内容是已经被获取实体标识的最大数值加 1。
我们要使用注释描述 Animal实体的标识由容器自动生成,只需要为它的标识字段提供 GeneratedValue注释,并且把它的 strategy属性设置为 GenerationType.AUTO, Animal实体类的代码片断如下:
清单 1. 标识由容器自动生成的 Animal 实体类
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Animal { @Id @GeneratedValue(strategy=GenerationType.AUTO) private long id; private String name; … }
保存 Animal实体的第一个实例时,OpenJPA 框架自动调用 SQL 语句 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID=0,从默认保存实体标识的 OPENJPA_SEQUENCE_TABLE表中获取实体的标识,如果不存在 ID为 0 的记录,OpenJPA 框架自动将实体的标识设置为 1。
容器管理实体标识的情况下,为了获得实体标识,应用程序将不得不频繁地和数据库交互,这会影响应用程序的运行效率。OpenJPA 中使用实体标识缓存机制解决这个问题。默认情况下,当应用程序第一次获取实体标识时,OpenJPA 框架从数据库中一次性获取 50 个连续的实体标识缓存起来,当下一次应用程序需要获取实体标识时,OpenJPA 将首先检测缓存中是否存在实体标识,如果存在,OpenJPA 将直接使用缓存中的实体标识,如果不存在,OpenJPA 框架将会从数据库中再次获取 50 个连续的实体标识缓存起来,如此类推。这样的处理方式可以大大减少由于获取实体标识而产生的数据库交互,提升应用程序的运行效率。
当实体标识成功获取之后,OpenJPA 框架会把当前实体标识的最大值 +1 后持久化到数据库中。由于实体标识缓存的原因,当我们第一次获取实体标识后,OpenJPA 会将 OPENJPA_SEQUENCE_TABLE表的 SEQUENCE_VALUE的值设置为 51,当 OpenJPA 多次从数据库中获取实体标识后,SEQUENCE_VALUE的值会以 50 为单位递增,变为 101、151、201 …。
OpenJPA 缓存的实体标识不是永久存在的,只能在同一个 EntityManagerFactory管理范围内起作用,也就是说,当获取实体标识的 EntityManagerFactory对象被关闭后,这些被获取的实体标识中没有用掉的那一部分标识就丢失了,这会造成实体标识的不连续。由同一个 EntityManagerFactory对象创建的 EntityManager上下文之间则能够共享 OpenJPA 框架获取的实体标识,这意味着,我们可以使用同一个 EntityManagerFactory对象创建多个 EntityManager对象,用它来持久化实体,然后关闭它,在持久化过程中所需要的实体表示将会使用同一个实体标识的缓存区,因此不会引起实体标识的丢失。
容器管理的实体标识还有一个非常重要的特性:所有被容器管理的实体标识都是共享的。不管 OpenJPA 容器中存在多少个不同的被容器管理的实体标识,它们都会从同一个实体标识缓存中获取实体标识。我们可以用下面的例子说明这种情况:假设 OpenJPA 容器中存在两个实体类 Dog和 Fish,它们的实体标识字段都是数值型,并且都由 OpenJPA 管理。当我们首先持久化一个 Dog对象时,它的实体标识将会是 1,紧接着我们持久化一个 Fish对象,它的实体标识就是 2,依次类推。
uuid-string
要使用 uuid-string 机制自动生成实体标识,我们需要将实体主键字段的 GeneratedValue注释的 strategy属性设置为 GenarationType.AUTO,然后将 GeneratedValue注释的 generator属性设置为 uuid-string。以 Animal 实体类为例,我们只需要将 Animal 实体修改为如下内容:
清单 2. 使用 uuid-string 机制自动生成实体标识
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Animal { @Id @GeneratedValue(strategy=GenerationType.AUTO, generator = "uuid-string") private String id; private String name; … }
uuid-hex
要使用 uuid-hex 机制自动生成实体标识,我们必须将实体主键字段的 GeneratedValue注释的 strategy属性设置为 GenarationType.AUTO,然后将 GeneratedValue注释的 generator属性设置为 uuid-hex。以 Animal 实体类为例,我们只需要将 Animal 实体修改为如下内容:
清单 3. 使用 uuid-hex 机制自动生成实体标识
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Animal {
@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator = "uuid-hex")
private String id;
private String name;
…
}
自增长字段
自增长字段是 HSQL、SQL Server、MySQL、DB2、Derby 等数据库提供的一种特性,用于为数据库的记录提供自动增长的编号,应用程序的设计者通常期望将实体标识的自动生成委托给数据库的这种特性,OpenJPA 框架中的实体标识能够满足应用程序设计者的要求,使用数据库的自增长字段为实体自动生成标识。
要将实体标识的自动生成委托给数据库的自增长字段特性,需要数据库和实体定义的双方配合才能够达到:首先,必须将实体标识字段对应的数据库列修改为自动增长列,另外还需要将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.IDENTITY。
我们以 Animal 实体在 HSQL 数据库中的持久化来说明如何使用自增长字段自动生成实体标识所需要采取的步骤:
首先,我们使用下面的 SQL 语句创建 Animal 表,把它的 ID字段设置为自动增长类型:
清单 4. 将 ID 字段设置为自动增长类型的 SQL 语句
CREATE TEXT TABLE ANIMAL ( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY, NAME VARCHAR(255) NOT NULL )
在数据库部分将表的主键字段设置为自动增长字段后,在实体 Animal的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.IDENTITY。Animal 实体类修改后的代码片段如下。
清单 5. 标识由自增长字段生成的 Animal 实体类
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Animal { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; private String name; … }
序列号(Sequence)
序列号是 Oracle、PostgreSQL 等数据库提供的一种特性,用于为数据库的记录提供自动增长的编号,使用 Oracle、PostgreSQL 等数据库应用程序的设计者通常期望将实体标识的自动生成委托给数据库的这种特性,OpenJPA 框架中的实体标识能够满足应用程序设计者的要求,使用数据库的序列号为实体自动生成标识。
要将实体标识的自动生成委托给数据库的序列号特性,需要数据库和实体定义的双方配合才能够达到:首先,必须在数据库中创建合适的序列号,另外还需要为实体标识字段提供 SequenceGenerator注释,设置它的参数,为实体类提供关于序列号的信息,同时将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.SEQUENCE,将 generator属性的值设置为 SequenceGenerator注释的 name属性的值。
我们以 Animal 实体在 Oracle 数据库中的持久化来说明如何使用自增长字段自动生成实体标识所需要采取的步骤:
首先,在 Oracle 数据库中运行下面的 SQL 语句创建名为 HelloWorldSequence的序列号,序列号支持 cache,大小为 50:
清单 6. 创建序列号的 SQL 语句
CREATE SEQUENCE HELLOWORLDSEQUENCE START WITH 0 INCREMENT BY 1 MINVALUE 1 CACHE 50 NOCYCLE NOORDER
然后,在 Oracle 数据库中,我们使用下面的 SQL 语句创建 ANIMAL表:
清单 7. 创建 ANIMAL 表
CREATE TABLE EOS52.ANIMAL
( ID CHAR(10), NAME VARCHAR2(100) NOT NULL, CONSTRAINT PK_ANIMAL PRIMARY KEY (ID ) )
在数据库部分创建合适的序列号和相应的数据库表后,在实体 Animal的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.SEQUENCE,设置它的 generator属性的值为 SeqGenerator。我们还需要为 id字段提供另外一个相关的注释 SequenceGenerator,设置它的 name属性为 SeqGenerator,设置它 sequenceName属性为 HelloWorldSequence。Animal 实体类修改后的代码片段如下。
清单 8. 标识由序列号生成的 Animal 实体类
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Animal { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SeqGenerator") @SequenceGenerator(name = "SeqGenerator", sequenceName = " HelloWorldSequence") private long id; private String name; … }
数据库表
除了使用容器生成的实体标识,或者借助于数据库的自增长字段或者序列号等方式生成实体标识之外,我们还可以选择借助数据库表来自动生成实体标识。原理是我们提供一个独立的数据库表,该表的主键列 ( 假设列名 ID) 记录实体编号的特征字符串 ( 假设存在一条记录的 ID为 customID),另外一列 ( 假设列名为 SEQUENCE_VALUE) 记录该特征字符串对应实体标识的最大值。编写实体代码时,我们指定实体标识由数据库表中指定的特征字符串 ( 如 customID) 对应的列 SEQUENCE_VALUE处理,当有新的实体被持久化时,容器将获取行 customID、列 SEQUENCE_VALUE对应的数值 +1 后作为新实体的标识,同时将该列的值也自动 +1。
要将实体标识的自动生成委托给数据库表,需要数据库和实体定义的双方配合才能够达到:首先,必须在数据库中创建合适的保存实体标识的表,另外还需要为实体标识字段提供 TableGenerator注释,设置它的参数,为实体类提供关于数据库表、字段的信息,同时将实体类中实体标识字段的 GeneratedValue注释的 stragety属性的值设置为 GenerationType.Table,将 generator属性的值设置为 SequenceGenerator注释的 name属性的值。
我们以 Animal 实体类来说明使用数据库表自动生成实体标识所需要采取的步骤:我们假设存在这样的场景,Animal 实体的标识由应用程序中自定义的数据库表 MY_KEYS自动生成,MY_KEYS表中有两列,一列是 KEYID,它保存实体标识的特征值,一列是 KEYVALUE,它保存实体当前的最大编号,除此之外,我们还决定使用 ANIMALID作为 Animal 实体标识的特征字符串。
首先,在数据库中使用下面的 SQL 语句创建名为 MY_KEYS的数据库表。在 OpenJPA 容器中,如果我们没有创建 MY_KEYS表,OpenJPA 容器将帮我们自动生成对应的表结构。
清单 9. 创建数据库表 MY_KEYS
CREATE TABLE MY_KEYS ( KEYID VARCHAR(255) NOT NULL, KEYVALUE BIGINT, PRIMARY KEY (KEYID) )
在数据库部分创建合适的数据库表后,在实体 Animal 的定义中,我们需要将 id字段 GeneratedValue注释的 stragety属性的值设置为 GenerationType.TABLE,设置它的 generator属性的值为 TableGenerator。我们还需要为 id字段提供另外一个注释 TableGenerator,设置它的 name属性为 TableGenerator,设置它的 table属性为 MYKEYS、pkColumnName属性为 KEYID、valueColumnName属性为 KEYVALUE、 ANIMALID属性为 ANIMALID。Animal 实体类修改后的代码片段如下。
清单 10. 标识由数据库表生成的 Animal 实体类
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Animal { @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = " TableGenerator ") @TableGenerator(name = " TableGenerator", table = "MY_KEYS", pkColumnName = "KEYID", valueColumnName = "KEYVALUE", pkColumnValue = "ANIMALID") private long id; private String name; … }
调用代码
上面的章节中我们学习了分别使用四种方式来自动生成实体的标识,由于这四种情况下,Animal 实体的标识都由 OpenJPA 和数据库协作后自动生成,对于开发者而言,这个过程是透明的,因此我们可以使用相同的方式来创建这些实体:创建新的 Animal 实例的时候不再需要为主键字段提供属性值,只需要设置 Animal 实例的非标识字段 name的值即可。下面的代码演示了 Animal 实例的持久化代码,请注意代码中并没有调用 Animal 实例的 setId 方法。
清单 11. Animal 实例的持久化代码
EntityManagerFactory factory = Persistence. createEntityManagerFactory( "jpa-unit", System.getProperties()); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Animal animal = new Animal(); // 此处不需要调用 animal 的 setId 方法 animal.setName("ba guai!"); em.persist(animal); em.getTransaction().commit(); em.close(); em2.close(); factory.close();
总结
本文介绍了开发者使用 OpenJPA 实现实体标识自动生成时可选择使用的注释,并且结合简单的例子,分别介绍了 OpenJPA 中实现容器管理的实体标识自动生成、结合数据库自增长字段、序列号、数据库表等特性实现实体标识自动生成时注释的具体用法和操作步骤。
发表评论
-
Eclipse,javaw 通过Proxifile代理ipv6协议问题解决
2015-03-17 18:06 2791myeclipse2010升级到myeclipse2014之后 ... -
初始化EHcache CacheManager时报java.net.UnknownHostException
2014-11-13 11:45 12510工程启动时,报一下异常: [wdfportal] [201 ... -
tomcat7可能带来的问题
2013-06-27 00:31 9831、struts标签校验更加严格,如果struts标签中存在嵌 ... -
iBatis执行insert后返回主键
2013-01-18 23:55 1646iBatis插入数据后,返回主键。级联操作很有用。省去了一次的 ... -
Shallow heap & Retained heap
2012-05-16 17:09 49290所有包含Heap Profling功能的工具(MAT, You ... -
Abator —— IBatis 代码生成工具
2012-04-03 18:31 19331、在eclipse安装abator插件http://ibat ... -
使用Eclipse远程调试Tomcat
2012-03-23 22:56 1510有些时候,调试不得不用外网,比如说做支付宝的支付接口,服务器后 ... -
Java compiler level does not match the version of the installed Java project fac
2012-03-02 11:32 1318问题现象:项目图标报错“Java compiler level ... -
WebService的事务处理
2012-03-01 15:03 1560如果你只是要解决两个系统之间的事务同步问题,可以采用判断服务是 ... -
线程池(java.util.concurrent.ThreadPoolExecutor)的使用
2012-02-29 15:50 2508一、简介 线程池类为 j ... -
myeclipse 颜色设置(保护视力)
2012-02-28 09:29 20871.window -> Preferences -> ... -
Quartz表达式解析
2012-02-08 14:40 807字段 允许值 允许的特 ... -
使用iBatis中报 java.sql.SQLException: 无效的列类型异常
2011-12-15 14:46 2241<!--Content表 插入应的 ... -
非常有用的proxool属性详细解说
2011-12-13 16:19 1610Proxool连接池是sourceforge下的一个开源项目, ... -
在工程中查找自己修改的所有代码
2011-12-09 17:41 1048在工程中查找自己修改的所有代码的方法: 1.工程右键 -&g ... -
如何在Eclipse中安装和使用ibatis插件Abator
2011-12-01 21:26 49741、获得abator: http://ibatis. ... -
newCachedThreadPool线程池
2011-11-20 11:35 43034public static ExecutorService n ... -
Apache Mina – 简单的客户端/服务端应用示例
2011-11-19 23:49 5526转自http://javasight.net/2011/05/ ... -
Class.forName()、Class.forName().newInstance() 、New 三者区别!
2011-11-15 09:18 1260终于明白为什么加载数据库驱动只用Class.forName() ... -
Apache MINA 快速入门指南
2011-11-13 12:04 1660最近用到Socket套接字编程,在服务器监听方面还没有具体思路 ...
相关推荐
在《用八叉树数据结构自动生成三维网格的算法设计》这篇论文中,作者详细探讨了八叉树数据结构在自动生成三维网格方面的应用,这在计算冶金学的数值计算领域中具有重要意义。本文将对论文中的关键知识点进行详细说明...
通过简单的配置,Ibator可以根据数据库表的信息自动生成相应的Java代码,包括Mapper接口、Mapper XML文件、DAO实现类以及实体类等,从而减轻开发者的负担。 首先,安装Ibator插件。下载名为"IbatorForEclipse1.2.1...
这个标题揭示了该软件工具的核心功能,即自动生成Hibernate实体以及与之相关的C#代码,同时具备支持多种数据库的能力。Hibernate是一个流行的Java对象关系映射(ORM)框架,它简化了数据库操作,通过将Java类映射到...
这里,id字段的值将由数据库自动生成,通常是通过自动递增。 5. `@Column`: 定义实体类的属性如何映射到表的列。英文为"Column Annotation",例如: ```java @Entity public class User { @Id private Long id; ...
总的来说,JeeSite代码生成器简化了开发过程,通过几步简单的配置和修改,就能自动生成一套完整的CRUD操作代码,大大减少了开发人员的工作量。同时,它也强调了模块化和权限管理,使得企业级应用的构建更加规范和...
这些场景是自动驾驶汽车驾驶情景与行驶环境的有机组合,它们既包括了实体元素,如车辆、行人等,也涵盖了这些实体执行的动作和它们之间的连接关系。 测试场景的作用至关重要,它贯穿于自动驾驶汽车的设计、研发、...
- **选择表**:首先选择需要生成代码的表,然后配置表的相关信息,包括表名、描述、实体类名称等。 - **字段配置**:对每个字段进行详细的配置,包括字段名、注释、物理类型、Java类型、属性名称、主键状态、是否...
文本到视频生成是指根据给定的文本描述自动生成对应视频的技术。这一过程涉及多个技术层面的挑战,如理解文本中的语义信息、生成连贯且逼真的视频内容等。早期的研究主要集中在解决基础的技术难题上,而随着深度学习...
总的来说,K8_PetShop三层代码生成器V1.0 Beat是针对PetShop项目的一次重要创新,它通过自动化代码生成,减轻了开发人员的工作负担,提高了开发效率,是K8编程小组在软件工程实践中的一个成功案例。对于熟悉三层架构...
通过CAPP系统,可以自动或半自动生成加工工序、选择加工设备和刀具,并规划生产流程。CAPP系统能够优化工艺路线,减少工序,提升生产效率和降低成本。 计算机辅助制造(CAM)是将计算机辅助设计产生的几何模型转化...
在制造业中,自动化生产线能提高生产效率、降低成本、保证产品质量,是现代工业生产的重要标志。 UG软件在设计自动化生产线时发挥着核心作用。它具备强大的建模工具,可以精确地模拟每一个组件的几何形状,包括复杂...
- 办公自动化(Office Automation,简称OA)指的是利用先进的科学技术,特别是信息技术,将一部分办公业务活动转移到非人类实体(如现代办公设备)中进行的一种变革。 - 它是由办公人员和办公设备共同组成的服务于...
点击"Generate"按钮,DesignModeler将根据草图自动生成一个名为"SurfaceSk"的表面体对象,这标志着2D表面体的创建完成。 接下来,回到Workbench环境,双击"Mesh"任务,DesignModeler创建的表面体会自动导入到网格化...
同时,自然语言处理技术也可以用于机器人、自动驾驶汽车等领域,极大地改变了我们的生活方式。 OpenAI GPT-2 模型是一个基于 transformer 的语言生成模型,能够生成高质量的文本,并且可以用于各种自然语言处理任务...
图像识别技术可以对行人、车辆、交通标志等实体进行识别,物体跟踪技术可以实现对这些实体的跟踪,立体视觉技术可以得到周围环境的三维信息。这些技术的完备组合,可以实现对周围物体的高精度感知和识别。 机器学习...
数据类提供了自动生成的`equals()`, `hashCode()`, 和 `toString()`等方法,方便比较和打印。 7. ** Kotlins的空安全与标志**: 在Kotlin中,我们可以利用可空类型(`?`)和非空断言(`!!`)来处理标志的空值情况...
可以通过 `hibernate.hbm2ddl.auto` 配置属性控制自动生成行为。 ##### 外部配置 除了通过注解配置实体映射之外,还可以使用 XML 文件或者基于 Java 的配置方式来定制更复杂的映射规则。 #### 总结 通过使用 ...
- **表结构**:对于每个经过审计的实体,Envers会自动生成一个新的表,通常命名为 `<实体表名>AUD`。 - **数据同步**:每当提交事务时,系统会自动记录历史数据到对应的审计表中。 - **DDL生成**:如果使用 `...