java Hibernate生成类型.IDENTITY未生成序列ID

6uxekuva  于 2022-12-10  发布在  Java
关注(0)|答案(2)|浏览(198)

bounty将在3天后过期。回答此问题可获得+100声望奖励。Ranjithkumar希望吸引更多人关注此问题。

在我的springboot应用程序中,当插入新行时,我注意到一个奇怪的问题。
我的id是按顺序生成的,但在我重新启动应用程序后,它从21开始。

范例:

第一次启动时,我插入3行-序列1、2、3生成的id
在重新启动第二次启动后,我插入了从21生成3行ID,因此ID为21,22...
每次重新启动它都会增加到20-这种增加模式总是20

引用我的数据库表(重新启动21后的1,2)

我的JPA实体

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Long id;

我尝试了一些stackoverflow解决方案,但不起作用
我试过了,没用

spring.jpa.properties.hibernate.id.new_generator_mappings=false

我想按1,2,3,4这样的顺序插入行。而不是像这样的1,2,21,22,如何解决这个问题?

7cwmlq89

7cwmlq891#

它与Hibernate用于递增序列值的Hi/Lo算法有关。阅读以下示例中的更多内容:https://www.baeldung.com/hi-lo-algorithm-hibernate
这是Hibernate使用的一种优化,它将数据库序列中的一些值消耗到池中(Java运行时),并在对表执行适当的INSERT语句时使用它们。如果关闭此优化并设置allocationSize=1,则所需的行为(id中没有间隔)是可能的(具有一定的精度,不总是),但是代价是为每个INSERT向DB发出两个请求。
示例给予了在抽象的上层发生了什么的想法。(内部实现更复杂,但这里我们不关心)

**场景:**用户在一段时间内插入21次
示例1(当前行为allocationSize=20

#1 insert: // first cycle 
   - need next MY_SEQ value, but MY_SEQ_PREFETCH_POOL is empty
   - select 20 values from MY_SEQ into MY_SEQ_PREFETCH_POOL   // call DB
   - take it from MY_SEQ_PREFETCH_POOL >> remaining=20-1
   - execute INSERT                                           // call DB

   #2-#20 insert:
   - need next MY_SEQ value, 
   - take it from MY_SEQ_PREFETCH_POOL >> remaining=20-i
   - execute INSERT                                           // call DB
 
   #21 insert: // new cycle 
   - need next MY_SEQ value, but MY_SEQ_PREFETCH_POOL is empty
   - select 20 values from MY_SEQ into MY_SEQ_PREFETCH_POOL   // call DB
   - take it from MY_SEQ_PREFETCH_POOL >> remaining=19
   - execute INSERT                                           // call DB

示例2(当前行为allocationSize=1

#1-21 insert:
   - need next MY_SEQ value, but MY_SEQ_PREFETCH_POOL is empty
   - select 1 value from MY_SEQ into MY_SEQ_PREFETCH_POOL     // call DB
   - take it from MY_SEQ_PREFETCH_POOL >> remaining=0
   - execute INSERT                                           // call DB

示例1:对数据库的调用总数为23
示例2:对数据库的调用总数为42

在这种情况下,在数据库中手动声明序列将没有帮助,因为例如在此语句中,
CREATE SEQUENCE ABC START WITH 1 INCREMENT BY 1 CYCLE CACHE 0;
我们只控制在DB内部运行时使用的“缓存”,它对Hibernate是不可见的。2当DB停止并再次启动时,它会影响序列间隙,但事实并非如此。
当Hibernate使用序列中的值时,这意味着序列的状态在DB端发生了变化。我们可以将其视为酒店房间预订:一家公司(Hibernate)在一家酒店(DB)预订了20个会议房间,但只有2个与会者到达。2这样,18个房间将一直空置,不能被其他客人使用。3在这种情况下,“预订期”是永久的。
有关如何使用序列配置Hibernate的更多详细信息,请访问:https://ntsim.uk/posts/how-to-use-hibernate-identifier-sequence-generators-properly
下面是一个关于老版本Hibernate的简短回答。不过它也有相关的想法:https://stackoverflow.com/a/5346701/2774914

相关问题