Hibernate 生成JPA 2序列的Postgresql中奇怪的id值

Hibernate 生成JPA 2序列的Postgresql中奇怪的id值,hibernate,postgresql,jpa-2.0,sequence,Hibernate,Postgresql,Jpa 2.0,Sequence,该实体在id列上具有以下注释: @Id @SequenceGenerator(name = "JOB_MISFIRE_ID_GENERATOR", sequenceName="job_misfire_sequence", allocationSize=10) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "JOB_MISFIRE_ID_GENERATOR") @Column(unique = true, nullabl

该实体在id列上具有以下注释:

@Id
@SequenceGenerator(name = "JOB_MISFIRE_ID_GENERATOR", sequenceName="job_misfire_sequence", allocationSize=10)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "JOB_MISFIRE_ID_GENERATOR")
@Column(unique = true, nullable = false)
private Long id;
在数据库中,我有以下内容:

CREATE SEQUENCE job_misfire_sequence
  INCREMENT 10
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 1;
@Id
@SequenceGenerator(name = "JOB_MISFIRE_ID_GENERATOR", sequenceName="job_misfire_sequence", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "JOB_MISFIRE_ID_GENERATOR")
@Column(unique = true, nullable = false)
private Long id;
CREATE SEQUENCE job_misfire_sequence
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 10;
序列用于获取列的默认值

ALTER TABLE job_misfires
ALTER COLUMN id SET DEFAULT nextval('job_misfire_sequence');
当我使用nextval(“作业缺火序列”)手动插入数据库时,一切都很好。当序列的当前值为1时,生成以下id值:

 SELECT nextval('job_misfire_sequence'); --> 1
 SELECT nextval('job_misfire_sequence'); --> 11
 SELECT nextval('job_misfire_sequence'); --> 21
 SELECT nextval('job_misfire_sequence'); --> 31
 SELECT nextval('job_misfire_sequence'); --> 1
 SELECT nextval('job_misfire_sequence'); --> 2
 SELECT nextval('job_misfire_sequence'); --> 3
 SELECT nextval('job_misfire_sequence'); --> 4
但是当hibernate向这个表中插入一行时,它会从这个序列中得到下一个值(在这个场景中是41),然后将它乘以10,并将其用作id值。这意味着插入的行现在具有id值410

我做错了什么?这种情况将导致冲突,因为hibernate没有使用序列提供的值。如果我正确理解了
allocationSize=10 在注释和 增量10 在序列中,应该保证hibernate只需每隔十个值从序列中请求一个新值。为什么没有发生这种情况?为什么序列中的值乘以10

我正在使用

  • Postgresql 9.0.3
  • 冬眠3.5.5
  • Hibernate JPA 2.0 api 1.0.0最终版

更新1:

正如在Internet上建议的那样,在注释中将allocationSize值设置为1可以解决此问题。现在,id值实际上是从db中的序列中获取的,我可以安全地在该表中手动插入行

但是:

  • allocationSize=1是否会导致性能问题
  • 序列中的值没有像hibernate中那样使用,而是乘以allocationSize值,这不是一个巨大的错误吗
  • 谁该受责备?冬眠
  • 有可用的修复程序吗
我的理解是,
nextVal('job\u misfire\u sequence')
将返回下一个序列值,从而返回所需的值。Hibernate可以对此进行抽象,并假定从DB返回的值是正确的。因此,您不需要
allocationSize=10
,因为数据库已经返回了正确的值。

我不知道Hibernate,但是当序列在PostgreSQL中使用缓存值创建时,缓存会按每个连接运行。这意味着,如果从不同会话(=连接)调用nextval(),也可能会看到这种行为

引自手册:

可能会得到意想不到的结果 如果缓存设置大于1,则 用于将 被多个用户同时使用 会议。每个会话将分配 并缓存连续序列值 在对序列的一次访问期间 对象并增加序列 对象的最后一个_值。那么, 下一个cache-1使用nextval 在该会话中,只需返回 预先分配的值,不接触 序列对象。有数字吗 已分配但未在内部使用 会话将在该会话结束时丢失 端部,从而在 序列

确保您阅读了手册中的“注意事项”部分: 这就是它的工作原理

将序列生成器与
allocationSize
一起使用时,Hibernate从序列中获取一个数字以生成
allocationSize
标识符。因此,在从序列中获得值
N
之后,它从
allocationSize*N
allocationSize*(N+1)-1生成标识符。然后从序列中获得下一个值,以生成下一组标识符。如果下一个值是
N+1
,则生成的标识符是连续的,因此它需要产生后续数字的sequence


因此,无需在序列定义中指定增量。

正确的方法如下:

CREATE SEQUENCE job_misfire_sequence
  INCREMENT 10
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 1;
@Id
@SequenceGenerator(name = "JOB_MISFIRE_ID_GENERATOR", sequenceName="job_misfire_sequence", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "JOB_MISFIRE_ID_GENERATOR")
@Column(unique = true, nullable = false)
private Long id;
CREATE SEQUENCE job_misfire_sequence
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 10;
在数据库中,我有以下内容:

CREATE SEQUENCE job_misfire_sequence
  INCREMENT 10
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 1;
@Id
@SequenceGenerator(name = "JOB_MISFIRE_ID_GENERATOR", sequenceName="job_misfire_sequence", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "JOB_MISFIRE_ID_GENERATOR")
@Column(unique = true, nullable = false)
private Long id;
CREATE SEQUENCE job_misfire_sequence
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 10;
现在,当我使用nextval(“作业缺火序列”)手动插入db时,一切都按预期进行。当序列的当前值为1时,生成以下id值:

 SELECT nextval('job_misfire_sequence'); --> 1
 SELECT nextval('job_misfire_sequence'); --> 11
 SELECT nextval('job_misfire_sequence'); --> 21
 SELECT nextval('job_misfire_sequence'); --> 31
 SELECT nextval('job_misfire_sequence'); --> 1
 SELECT nextval('job_misfire_sequence'); --> 2
 SELECT nextval('job_misfire_sequence'); --> 3
 SELECT nextval('job_misfire_sequence'); --> 4
现在hibernate也可以像我期望的那样工作。当我在一个会话中插入了这4行之后,它再插入一行时,返回给hibernate的序列值是11。Hibernate使用它作为第一条记录的id值,11作为下一条记录的id值,依此类推。因为我将缓存设置设置为10 in db,hibernate现在只需要调用序列一次,然后就可以使用10个顺序id值。我确认确实如此,id值没有重叠

因此,关键点是:

  • 必须在注释中使用allocationSize=1
如果要优化db插入的性能,请使用

  • 在db中使用值大于1的缓存设置,但不要触摸allocationSize
要获得好的顺序id值

  • 必须使用增量1

缓存设置实际上没有在我的序列中使用。他们在手册中提到的意外结果与生成的id值之间的差距有关。这决不是问题。重叠的id值可能是错误的,但使用CACHE>1不会导致这种情况。是的,hibernate绝对应该期望db的值是正确的。但是allocationSize的文档说:“当从序列中分配序列号时,增加的量。”它没有提到乘法。使用allocationSize 100和INCREMENT 100应该使hibernate正常工作,这样它只需要请求一次序列值,然后就可以安全地将id值分配给下一个100记录。至少我是这样理解的。我知道这可能有点唠叨,但您对hibernate在创建每个新对象时发送查询以获取下一个序列号有问题吗?这就是我的代码目前的工作方式。。。对于基准测试:获取约650000个序列号