You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

    // 其他字段及方法
}

验证步骤

  1. 启动应用后插入第一条新数据,检查生成ID是否符合旧版逻辑
  2. 批量插入多条数据,确认ID落在预期范围内(如6000-6099)
  3. 验证新生成ID不会与已存在的旧ID重复

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:21:01