Hibernate IDENTITY与SEQUENCE实体标识符生成器

时间:2013-07-22 05:17:27

标签: java performance hibernate jpa java-ee

article说:

  

与身份不同,列值的下一个数字将从内存中检索,而不是从磁盘中检索 - 这使得序列明显快于身份

这是否意味着身份证件来自磁盘?如果是,那么哪个磁盘和如何

使用序列,我可以在日志中看到在插入新记录时对DB的额外选择查询。但在身份的情况下,我没有在日志中找到额外的选择查询。 那么序列如何变得比身份更快

4 个答案:

答案 0 :(得分:18)

序列使用的策略:

在插入新行之前,请向数据库询问下一个序列值,然后插入此行并返回序列值作为ID。

身份使用的策略:

插入行而不指定ID的值。插入行后,向数据库询问上次生成的ID。

因此在两种情况下查询的数量都相同。 但是,Hibernate默认使用一种对序列生成器更有效的策略。事实上,当它要求下一个序列值时,它会在内存中保留50(即dafault,IIRC和它的可配置)下一个值,并在接下来的50个插入中使用这50个下一个值。只有在插入50次之后,它才会进入数据库以获得50个下一个值。这极大地减少了自动ID生成所需的SQL查询数量。

身份策略不允许这样的优化。

答案 1 :(得分:13)

IDENTITY generator始终需要数据库命中来获取主键值,而不等待flush将当前entity state transitions与数据库同步。

因此IDENTITY生成器不能很好地与Hibernate write-behind第一级缓存策略配合使用,因此对于IDENTITY生成器禁用JDBC批处理。

序列生成器可以从数据库值预分配中受益,您甚至可以使用HI/LO optimization strategy

在我看来,最好的生成器是pooled and pooled-lo sequence generators。这些生成器将批处理友好的序列生成器与客户端值生成优化相结合,该优化与其他可能插入行的数据库客户端兼容,而不了解我们的生成策略。

无论如何,你永远不应该选择TABLE生成器,因为it performs really bad。如果您需要可移植性,可以使用覆盖配置来解决它,如this article中所述。

答案 2 :(得分:0)

虽然我个人对Hibernate不熟悉,但据我所知,使用Identity基本上意味着Hibernate会检查数据库中下一个可能的id值是什么,并为它保留一个值。

对于序列,您基本上告诉Hibernate根据您提供的特定序列生成下一个值。因此,它必须通过查看下一个可能的id值来实际计算下一个id。因此,额外的查询被触发。

答案 3 :(得分:0)

也许这会回答你的问题:

  

与行所生成的标识列值不同   插入后,应用程序可以获取下一个序列号   通过调用NEXT VALUE FOR函数插入行。序列   即使数字,也会在调用NEXT VALUE FOR时分配编号   永远不会插入表中。 NEXT VALUE FOR功能可以   用作表定义中列的默认值。使用   sp_sequence_get_range获取一系列多个序列号   一次。

您可以找到详细信息here

身份不需要额外的选择查询,因为Identity是依赖于表的,而Sequence是独立于表的,但是因为这样我们甚至可以在创建行之前得到序列(当你执行session.save(T实体)时,序列是甚至在您提交事务之前生成)。

序列: 您创建或更新实体 - >每次保存实体 - > hibernate获取下一个序列值 - >您的程序在所有进程完成后返回值,无例外或回滚 - >你提交所有交易 - > hibernate插入所有完整的实体

identity:提交事务时,插入不完整的实体(必须从标识列中获取)。所以序列的 INSERT 命令肯定比较慢,但优点是如果取消插入,则计数不会增加。