使用JPA和Hibernate时如何选择ID生成策略

113

我正在阅读Hibernate参考指南和《使用Hibernate进行Java持久化》书籍中的ID生成部分。

Hibernate和JPA结合可以提供许多选项。

我想进一步了解如何选择特定的id生成策略的文档。

我也在寻找临界点。

例如,hilo策略预计可以降低竞争。 我认为这种选择必须存在折衷。

我希望了解相关的权衡利弊。

是否有任何相关的文献可供参考?

4个回答

98
这个API文档非常清晰明了。
所有生成器都实现了 org.hibernate.id.IdentifierGenerator 接口。这是一个非常简单的接口。某些应用程序可以选择提供自己专门的实现,但 Hibernate 提供了一系列内置实现。内置生成器的快捷名称如下: increment:生成 long、short 或 int 类型的标识符,只有当没有其他进程向同一表插入数据时才是唯一的。在集群中不要使用。 identity:支持 DB2、MySQL、MS SQL Server、Sybase 和 HypersonicSQL 中的 identity 列。返回的标识符为 long、short 或 int 类型。 sequence:在 DB2、PostgreSQL、Oracle、SAP DB、McKoi 中使用序列或在 Interbase 中使用生成器。返回的标识符为 long、short 或 int 类型。 hilo:使用 hi/lo 算法高效地生成 long、short 或 int 类型的标识符,给定一个表和列(默认情况下分别为 hibernate_unique_key 和 next_hi)作为 hi 值的来源。hi/lo 算法生成的标识符仅对特定数据库唯一。 seqhilo:使用 hi/lo 算法高效地生成 long、short 或 int 类型的标识符,给定一个命名的数据库序列。 uuid:使用 128 位 UUID 算法生成类型为字符串的标识符,在网络内唯一(使用 IP 地址)。UUID 编码为长度为 32 的十六进制数字字符串。 guid:在 MS SQL Server 和 MySQL 上使用数据库生成的 GUID 字符串。 native:根据底层数据库的功能选择 identity、sequence 或 hilo。 assigned:允许应用程序在调用 save() 之前为对象分配标识符。如果没有指定元素,则这是默认策略。 select:通过选择某些唯一键并检索主键值,检索由数据库触发器分配的主键。 foreign:使用另一个关联对象的标识符。通常与主键关联一起使用。 sequence-identity:一种专门的序列生成策略,利用数据库序列进行实际值生成,但结合 JDBC3 getGeneratedKeys 在插入语句执行过程中返回生成的标识符值。此策略仅受支持于面向 JDK 1.4 的 Oracle 10g 驱动程序。由于 Oracle 驱动程序中的错误,这些插入语句的注释被禁用。
如果您正在构建一个并发用户不多的简单应用程序,可以使用增量、标识符、hilo等方法。这些方法易于配置,不需要在数据库内部进行太多编码。
根据您的数据库选择序列或GUID,这是更安全和更好的选择,因为id生成将在数据库内部进行。
更新: 最近我们遇到了一个关于identity的问题,这个问题是由于基本类型(int)引起的,通过使用包装类型(Integer)进行修复。

1
我已经更新了我的回答。实际上,increment, identity, hilo等方法更简单。但它们并不适用于企业应用程序。保留所有选项并不是问题,但请确保您使用最适合您的选项! - ManuPK
是的。到目前为止,我还没有赞同或接受的特权。 - user1317764
我最近在一个高并发插入和读取但没有更新的表中使用了Hilo策略。我计划进行一些实验来找到统计数据,并将其发布。 - user1317764
Hilo的优点在于它是跨数据库的,因为它基于一个简单的表格。我在一个需要支持MySQL、Oracle和MSSQL的应用程序中使用它。 - Pierre Henry
你说sequenceguid的ID生成是在数据库内部进行的。你是否意味着incrementidentity等不是在数据库内部进行的? - Kumar Manish
显示剩余3条评论

65

基本上,你有两个主要选择:

  • 你可以自己生成标识符,并使用指定的标识符。
  • 你可以使用@GeneratedValue 注释,Hibernate将为你分配标识符。

对于生成的标识符,你有两个选择:

  • UUID 标识符。
  • 数字标识符。

对于数字标识符,你有三个选择:

只有当你不能使用 SEQUENCE(例如 MySQL)时,IDENTITY 才是一个好的选择,因为它禁用了JDBC批量更新。

SEQUENCE 是首选的选项,特别是与像 pooledpooled-lo 这样的标识符优化器一起使用。

应该避免使用 TABLE,因为它使用单独的事务来获取标识符和行级锁定,这会导致扩展性下降。


20


前一段时间,我写了一篇关于Hibernate键生成器的详细文章:http://blog.eyallupu.com/2011/01/hibernatejpa-identity-generators.html

选择正确的生成器是一项复杂的任务,但尽早选择正确的生成器非常重要,因为晚期的迁移可能会成为噩梦。

有点离题,但这是一个提出通常被忽视的观点的好机会,即在应用程序之间(通过API)共享键。个人而言,我总是喜欢使用代理键,如果我需要将我的对象与其他系统通信,我不会暴露我的键(即使它是代理键)-我使用额外的“外部键”。作为一名顾问,我已经看到过不止一次使用对象键(“它就在那里,让我们使用它”方法)的“伟大”系统集成,只发现一两年后一方存在键范围或类似问题,需要对公开内部键的系统进行深度迁移。公开您的键意味着向外部约束公开您代码的基本方面,这些约束实际上不应该公开。


3

我认为这个讲座非常有价值,其中第三点总结了这些生成器,并给出了一些性能分析和使用每个生成器时的指导方针。


9
那个视频看起来非常熟悉。 - Vlad Mihalcea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接