实体在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;
序列用于获取列的默认值。
ALTER TABLE job_misfires
ALTER COLUMN id SET DEFAULT nextval('job_misfire_sequence');
当我使用nextval('job_misfire_sequence')手动插入数据库时,一切正常。当序列的当前值为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
但是当hibernate在这个表中插入一行时会发生什么呢?它得到了这个序列的下一个值(在这个场景中是41)并将它乘以10并将其用作id值。这意味着插入的行现在具有id值410。
我做错了什么?这种情况会导致冲突,因为hibernate没有使用序列提供的值。如果我理解了相关的组合 allocationSize = 10 在注释和 增量10 在序列中应该保证hibernate只需要每十个值从序列中请求一个新值。为什么这不会发生?为什么序列中的值乘以10?
我正在使用
更新1:
正如互联网周围建议的那样,在注释中将allocationSize值设置为1可以解决此问题。现在id值实际上取自db中的序列,我可以安全地在该表中手动插入行。
可是:
答案 0 :(得分:7)
执行此操作的正确方法似乎如下:
@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('job_misfire_sequence')手动插入数据库时,一切都按预期工作。当序列的当前值为1时,产生以下id值:
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值,依此类推。因为我在db中将CACHE设置设置为10,所以hibernate现在只需要调用一次序列,然后可以使用10个连续的id值。我确认情况确实如此,并且id值不重叠。
所以,关键点是:
如果要优化数据库插入的性能,请使用
获得不错的顺序id值
答案 1 :(得分:0)
我理解它的方式,nextVal('job_misfire_sequence');
将返回下一个SEQUENCE值,因此您需要的值。 Hibernate可以从中抽象出来,并假设从DB返回的值是正确的。因此,你不需要
allocationSize=10
,因为数据库已经返回了正确的值。
答案 2 :(得分:0)
我不知道Hibernate,但是当在PostgreSQL中使用缓存值创建序列时,缓存在每个连接的基础上运行。这意味着如果从不同的会话(=连接)调用nextval(),您可能也会看到此行为。
手册中的引用:
可能会获得意外结果 如果缓存设置大于1 用于序列对象 由多个同时使用 会话。每个会话都将分配 并缓存连续的序列值 在一次访问序列期间 对象并增加序列 对象的last_value。然后, nextval的下一个cache-1用法 在那个会话中只需返回 未分配的预分配值 序列对象。所以,任何数字 分配但未在a。中使用 会话将在该会话中丢失 结束,导致“洞” 序列
请务必阅读手册中的“注释”部分: http://www.postgresql.org/docs/current/static/sql-createsequence.html
答案 3 :(得分:0)
这就是它的工作原理。
当使用带有allocationSize
的序列生成器时,Hibernate从序列中获取单个数字以生成allocationSize
个标识符。因此,在从序列中获得值N
后,它会生成从allocationSize * N
到allocationSize * (N + 1) - 1
的标识符。然后它从序列中获取下一个值以生成下一组标识符。如果下一个值是N + 1
,则生成的标识符是连续的,因此它期望产生后续数字的seqeunce。
因此,无需在序列定义中指定increment
。