You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java GeneratedValue序列ID异常:allocationSize=1作用解析及有效性确认

问题解析与解答

1. 未设置allocationSize时ID数值偏大的原因

这其实是JPA序列生成器的默认预分配机制在搞事情:

  • 当你没显式指定allocationSize时,JPA(比如Hibernate这类常用实现)默认的allocationSize值是50。
  • 意思就是,每次应用启动或者预分配的ID用完时,它会一次性从数据库的FEATURE_INSTALLED_SEQ序列里捞50个ID存在内存里,之后新插入实体时直接从内存里取ID,不用每次都去数据库请求。
  • 这就导致数据库里的序列值会直接跳50(比如从1跳到51,再跳到101),而你实际插入的ID是内存里逐个分配的(1、2、3…50)。如果中途重启应用,那些预分配但没用到的ID就浪费了,下次会再取50个,所以你看到的数据库序列数值会比实际用的ID大很多,本质是预分配带来的“数值跳跃”。

2. allocationSize=1代码的有效性确认

你设置allocationSize = 1后的代码完全有效,刚好能解决上面的问题:

  • 这时JPA会每次插入实体都实时去数据库序列取最新值,不再预分配批量ID,数据库序列的增长步长和你实际插入的ID会完全对应,不会再出现数值大幅跳跃的情况。
  • 要注意的是:得确保数据库里FEATURE_INSTALLED_SEQ序列的INCREMENT BY参数也是1(这一般是默认值),如果序列的步长不是1,那allocationSize必须和序列步长保持一致,不然会出现ID冲突或者序列值浪费的问题。

3. 关于FEATURE_INSTALLED_ID为NULL时的触发器的注意事项

这里要重点留意触发器和JPA序列生成的冲突问题:

  • 当你设置allocationSize=1后,JPA在插入实体前就会从序列拿到ID并赋值给featureInstalledId字段,所以插入到数据库时这个字段不会是NULL,触发器不会被触发。
  • 如果你的触发器是用来在FEATURE_INSTALLED_ID为NULL时自动生成ID(比如也用同一个序列),那现在JPA已经提前占了序列值,触发器再去取的话就会导致ID重复,引发主键冲突。
  • 建议你统一ID生成方式:要么全用JPA的序列生成,要么禁用JPA的自动生成逻辑,只用触发器生成ID,避免两者同时工作出问题。

内容的提问来源于stack exchange,提问作者Adder

火山引擎 最新活动