Spring Boot 1.3.4迁移至3.3.2:Hibernate序列ID生成问题求助
解决方案
方案1:修改序列生成器优化器(推荐)
Spring Boot 3.3.2搭配的Hibernate 6,默认序列优化器从旧版的hilo改为了pooled-lo,这是ID生成逻辑变化的核心原因。只需在@SequenceGenerator中显式指定optimizer = "hilo",即可沿用旧版ID生成逻辑:
import jakarta.persistence.*; @Entity public class YourEntity { @Id @SequenceGenerator( name = "entity_seq", sequenceName = "YOUR_ORACLE_SEQ", // 替换为你的数据库序列名 allocationSize = 100, optimizer = "hilo" // 指定旧版优化器 ) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity_seq") private Long id; // 其他字段、构造方法及Getter/Setter }
hilo优化器的逻辑是:从序列获取高位值v,生成v * allocationSize到v * allocationSize + allocationSize - 1范围内的ID,完全匹配你描述的旧版公式generated_id = (序列值 * increment_size) + 偏移量(偏移量从0开始)。
方案2:自定义标识符生成器(完全复刻旧逻辑)
如果方案1无法满足需求,可自定义生成器完全对齐旧版逻辑:
1. 实现自定义生成器类
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGenerator; import org.hibernate.query.Query; import java.io.Serializable; import java.util.Properties; public class LegacySequenceGenerator implements IdentifierGenerator { private String sequenceName; private int allocationSize; private String tableName; @Override public void configure(org.hibernate.type.Type type, Properties params, org.hibernate.service.ServiceRegistry serviceRegistry) { sequenceName = params.getProperty("sequence_name"); allocationSize = Integer.parseInt(params.getProperty("allocation_size", "1")); tableName = params.getProperty(ENTITY_NAME); } @Override public Serializable generate(SharedSessionContractImplementor session, Object object) { // 查询表中当前最大ID String maxIdSql = String.format("SELECT MAX(id) FROM %s", tableName); Query<Number> maxQuery = session.createNativeQuery(maxIdSql, Number.class); Number maxId = maxQuery.uniqueResult(); long nextBaseId; if (maxId == null || maxId.longValue() == 0) { // 表为空时,从序列获取初始值并计算基准ID String seqSql = String.format("SELECT %s.NEXTVAL FROM DUAL", sequenceName); Query<Number> seqQuery = session.createNativeQuery(seqSql, Number.class); nextBaseId = seqQuery.uniqueResult().longValue() * allocationSize; } else { // 按旧版逻辑计算下一个基准ID nextBaseId = (maxId.longValue() / allocationSize + 1) * allocationSize; } return nextBaseId; } }
2. 在实体类中使用自定义生成器
import jakarta.persistence.*; @Entity @Table(name = "YOUR_TABLE") public class YourEntity { @Id @GenericGenerator( name = "legacy_generator", strategy = "com.your.package.LegacySequenceGenerator", // 替换为你的生成器类路径 parameters = { @Parameter(name = "sequence_name", value = "YOUR_ORACLE_SEQ"), @Parameter(name = "allocation_size", value = "100") } ) @GeneratedValue(generator = "legacy_generator") private Long id; // 其他字段及方法 }
验证步骤
- 启动应用后插入第一条新数据,检查生成ID是否符合旧版逻辑
- 批量插入多条数据,确认ID落在预期范围内(如
6000-6099) - 验证新生成ID不会与已存在的旧ID重复
内容的提问来源于stack exchange,提问作者Avinash Padmanabuni
相关产品推荐
相关产品推荐

