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

Spring Boot 2转3:Hibernate旧HiLo生成器迁移@TableGenerator初始ID不一致

解决Spring Boot 3迁移后@TableGenerator与旧MultipleHiLoPerTableGenerator的ID序列匹配问题

问题核心差异

旧MultipleHiLoPerTableGenerator与新@TableGenerator的核心逻辑冲突点:

  • 旧生成器:读取数据库seq_value后,先使用[当前值, 当前值+max_lo]区间(如seq_value=0时生成0-49),使用完区间后再将seq_value递增为50
  • 新生成器(含legacy-hilo优化器):先将数据库seq_value递增,再使用[新值, 新值+allocationSize-1]区间(如原seq_value=0时,先增到50再生成50-99,或因初始值逻辑生成1-50)
    这种读写顺序+区间偏移的差异,导致多应用共享Oracle库时出现ID重复。

解决方案

方案1:自定义Hibernate ID优化器(精准匹配旧逻辑)

通过自定义优化器完全复刻旧生成器的"先使用、后递增"逻辑:

public class LegacyHiLoOptimizer extends AbstractOptimizer {
    private long lastValue;
    private long hi;
    private long lo;
    private final long maxLo;

    public LegacyHiLoOptimizer(Class<?> returnClass, int incrementSize) {
        super(returnClass, incrementSize);
        this.maxLo = incrementSize - 1; // allocationSize=50对应maxLo=49,对齐旧逻辑
    }

    @Override
    public synchronized Serializable generate(AccessCallback callback) {
        if (lo > maxLo) {
            // 耗尽当前区间时,读取数据库值并做偏移,模拟旧逻辑的"先用后增"
            hi = callback.getNextValue() - 1;
            lo = 0;
        }
        lastValue = hi * (maxLo + 1) + lo++;
        return convert(lastValue);
    }

    @Override
    public long getLastValue() {
        return lastValue;
    }

    @Override
    public boolean applyIncrementSizeToSourceValues() {
        return false;
    }
}

配置使用自定义优化器:

spring.jpa.properties.hibernate.id.optimizer.pooled.preferred=com.yourpackage.LegacyHiLoOptimizer

保持@TableGenerator参数与旧结构一致:

@TableGenerator(name = "tk_sequence", 
        table = "hibernate_seq", 
        pkColumnName = "seq_name",
        pkColumnValue = "seq_token", 
        valueColumnName = "seq_value", 
        allocationSize = 50, 
        initialValue = 0)

方案2:调整数据库初始值+生成器参数(快速适配)

无需自定义代码,通过参数偏移抵消逻辑差异:

  1. 调整数据库hibernate_seq表中seq_value的值:将当前值减去allocationSize(如当前值为50则改为0)
  2. 修改@TableGenerator参数:
@TableGenerator(name = "tk_sequence", 
        table = "hibernate_seq", 
        pkColumnName = "seq_name",
        pkColumnValue = "seq_token", 
        valueColumnName = "seq_value", 
        allocationSize = 50, 
        initialValue = -49)
  1. 配置优化器为legacy-hilo:
spring.jpa.properties.hibernate.id.optimizer.pooled.preferred=legacy-hilo

此配置会让新生成器第一个区间为0-49,后续逻辑自动对齐旧生成器的区间划分。

方案3:原生SQL+触发器控制(最稳妥)

通过数据库层面逻辑完全复刻旧生成器行为:

  1. 创建存储过程,实现"读取当前seq_value生成ID区间,使用后递增seq_value"的逻辑
  2. 实体类ID字段配置调用存储过程:
@GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-seq-generator")
@GenericGenerator(name = "custom-seq-generator",
        strategy = "org.hibernate.id.enhanced.TableGenerator",
        parameters = {
                @Parameter(name = "table", value = "hibernate_seq"),
                @Parameter(name = "pk_column_name", value = "seq_name"),
                @Parameter(name = "pk_column_value", value = "seq_token"),
                @Parameter(name = "value_column_name", value = "seq_value"),
                @Parameter(name = "optimizer", value = "none"),
                @Parameter(name = "increment_size", value = "50")
        })
  1. 配合Oracle触发器,在插入数据前调用存储过程生成ID,插入完成后更新seq_value。

验证要点

  • 确认第一个ID区间为0-49,后续区间依次为50-99、100-149等,与旧生成器完全一致
  • 多应用同时生成ID时无重复
  • 应用重启后,ID生成从上次中断的区间继续,无断档或重复

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 21:30:20