Hibernate 和 DB2 序列的奇怪行为

发布于 2024-08-21 06:10:28 字数 641 浏览 2 评论 0原文

我将 Hibernate 与 Spring 和 DB2 一起使用。我正在使用序列来生成实体的主键。所有实体都使用相同的序列 HIBERNATE_SEQUENCE,这是 hibernate 默认值。

问题在于,最终进入主键的值大约比 HIBERNATE_SEQUENCE 返回的值高 10 倍。

例如,在将新行插入到 tbl 后出现这种情况:

select max(id) as primary_key, nextval for hibernate_sequence sequence_value from tbl ;

primary_key sequence_value
501483661   50148373

我已经在所有实体的超类中像这样映射了主键:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE)
   private Integer id;

我希望 hibernate 使用从序列中获取的那些值,而不是序列值乘以 10这样做的正确方法是什么?

I am using Hibernate with Spring and DB2. I am using sequences to generate primary key for entities. All entities use the same sequence HIBERNATE_SEQUENCE, which is the hibernate default.

The problem is that values that end up into primary keys are about 10 times higher than those returned by the HIBERNATE_SEQUENCE.

For example this situation just after a new row is inserted to tbl:

select max(id) as primary_key, nextval for hibernate_sequence sequence_value from tbl ;

primary_key sequence_value
501483661   50148373

I have mapped primary key like this, in super class for all entities:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE)
   private Integer id;

I'd like that hibernate uses those values it fetches from the sequence, not sequence values multiplied by 10. What is the correct way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我们的影子 2024-08-28 06:10:28

Hibernate 似乎执行以下操作:

当 hibernate 需要主键时,它将从序列中获取值。 Hibernate 将从单个序列值生成多个主键值。例如,hibernate将保留一个内部计数器,其值附加到序列值以获取主键值。当内部计数器达到其极限时,计数器将重置,从序列中获取新值,并且主键过程重新开始。

例如:

  1. 从sequence获取的值为123。获取的序列值按会话存储。
  2. 对于当前会话,生成的主键为 1230、1231、1232、1233、...、1238、1239。计数器值连接到步骤 1 中获得的序列值。需要时生成键。
  3. 现在主键生成过程全部重新开始。转到 1。

这会导致以下效果:

  • 数据库序列值有效地乘以 10
  • Hibernate 不必为其进行的每个数据库插入读取数据库。上述算法将序列读取的数量减少到 10%(当在单个会话中进行大量插入时)。
  • 所有其他非 Hibernate 应用程序都必须使用类似的算法从序列生成主键,否则在某些时候会出现主键冲突

要使 Hibernate 使用从序列获得的实际值,可以使用以下映射:

@Id
@GeneratedValue(generator="hibernate_sequence")
@GenericGenerator(strategy="sequence", name="hibernate_sequence")
private Integer id;

Hibernate seems to do following:

When hibernate needs a primary key it will fetch the value from sequence. Hibernate will generate several primary key values from single sequence values. For example hibernate will keep a internal counter whose value is appended to sequence value to obtain the primary key value. When the internal counter hits its limit the counter is reset, a new value from sequence is obtained and primary key process starts all over again.

For example:

  1. Value obtained from sequece is 123. The obtained sequence value is stored per session.
  2. For current session the generated primary keys are 1230, 1231, 1232, 1233, ..., 1238, 1239. A counter value is concatenated to sequence value obtained in step 1. A key is generated when needed.
  3. Now primary key generation process start all over. Goto 1.

This causes following effects:

  • database sequence value is effectively multiplied by 10
  • Hibernate does not have to make a database read for every DB insert it makes. The above algorithm cuts the number of sequence reads down to 10% (when doing a lot of inserts in single session).
  • every other non-hibernate application must use similar algorithm to generate primary keys from sequence, otherwise there will be primary key conflicts at some point

To make hibernate use actual values obtained from sequence, this mapping can be used:

@Id
@GeneratedValue(generator="hibernate_sequence")
@GenericGenerator(strategy="sequence", name="hibernate_sequence")
private Integer id;
二货你真萌 2024-08-28 06:10:28

我解决了这个问题,在@SequenceGenerator注释中将allocationSize设置为1。

示例:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GENERATOR")
   private Integer id;

和实体:

@SequenceGenerator(name = "SEQ_GENERATOR", sequenceName = "MY_SEQUENCE", allocationSize = 1)
public class MyEntity extends AbstractEntity {

I solved this problem setting allocationSize to 1 in @SequenceGenerator annotation.

Example:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GENERATOR")
   private Integer id;

and the entity:

@SequenceGenerator(name = "SEQ_GENERATOR", sequenceName = "MY_SEQUENCE", allocationSize = 1)
public class MyEntity extends AbstractEntity {
水中月 2024-08-28 06:10:28

DB2 createequence 命令上有一些选项可能会影响这一点。 INCRMENT_BY 表示每次调用 nextval 时要增加多少值。使用 NO_ORDER 的 CACHE 保留一定数量的值,因此如果多个连接使用相同的序列,它们可以更快地获取值,但代价是值乱序。在深入研究 Hibernate 之前,我会首先检查序列是如何创建的。从查看 Hibernate 代码来看,它非常简单 - 查看 DB2Dialect,您可以看到它用于获取序列值的 sql。

There are a few options on the DB2 create sequence command that might affect this. INCREMENT_BY says how much to increase the value with each call to nextval. CACHE with NO_ORDER reserves a certain number of values so if multiple connections are using the same sequence they can get values faster at the cost of the values being out of order. I would check to see how the sequence was created first before digging into Hibernate. From looking at the Hibernate code, it's pretty straightforward - look at DB2Dialect and you can see the sql it uses to get the sequence value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文