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

如何实现带字符递增的高效Alphanumeric ID生成?Hibernate咨询

实现前缀字母自动递增的字母数字ID生成器

看起来你已经有了一个基础的ID生成器,但需要实现数字段到9999时前缀字母自动进位的逻辑(比如RxT-AA9999之后自动生成RxT-AB0001)。下面是具体的解决方案,基于你现有的Hibernate SequenceStyleGenerator扩展来改造:

核心思路

我们可以把ID拆成三部分:

  1. 固定前缀:比如RxT-,这部分始终不变
  2. 可变字母段:从AA开始,每10000个ID自动进位(AA→AB→...→AZ→BA→...→ZZ)
  3. 数字段:从0001到9999,循环递增,数字满了触发字母段进位

实现的关键是把数据库序列的连续值,映射成「字母段索引 + 数字段」的组合:

  • 序列值1~10000 → 字母段AA + 数字0001~9999
  • 序列值10001~20000 → 字母段AB + 数字0001~9999
  • ...以此类推,直到ZZ9999

修改后的ID生成器代码

public class UserIdGenerator extends SequenceStyleGenerator {
    // 固定前缀参数(比如"RxT-")
    public static final String FIXED_PREFIX_PARAMETER = "fixedPrefix";
    public static final String FIXED_PREFIX_DEFAULT = "";
    private String fixedPrefix;

    // 数字部分的位数(比如4位对应0001-9999)
    public static final String DIGIT_LENGTH_PARAMETER = "digitLength";
    public static final int DIGIT_LENGTH_DEFAULT = 4;
    private int digitLength;
    private int maxDigitValue; // 计算得到的数字最大值,比如4位就是9999

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        // 获取数据库序列的下一个值(从1开始)
        Long sequenceValue = (Long) super.generate(session, object);
        
        // 计算数字段:确保范围在1~maxDigitValue之间
        long digitPart = (sequenceValue - 1) % maxDigitValue + 1;
        // 计算字母段的索引:每maxDigitValue个序列值,字母段进一位
        long letterIndex = (sequenceValue - 1) / maxDigitValue;
        
        // 将索引转换为两位大写字母(0→AA,1→AB,...675→ZZ)
        String letterPart = convertIndexToLetters(letterIndex);
        // 格式化数字段为固定位数
        String formattedDigit = String.format("%0" + digitLength + "d", digitPart);
        
        return fixedPrefix + letterPart + formattedDigit;
    }

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        super.configure(LongType.INSTANCE, params, serviceRegistry);
        fixedPrefix = ConfigurationHelper.getString(FIXED_PREFIX_PARAMETER, params, FIXED_PREFIX_DEFAULT);
        digitLength = ConfigurationHelper.getInt(DIGIT_LENGTH_PARAMETER, params, DIGIT_LENGTH_DEFAULT);
        maxDigitValue = (int) Math.pow(10, digitLength) - 1; // 计算数字最大值:比如4位→10^4-1=9999
    }

    // 将数字索引转换为两位大写字母的工具方法
    private String convertIndexToLetters(long index) {
        // 两位字母最多支持676种组合(AA~ZZ),超出可以扩展为三位字母
        if (index < 0 || index > 675) {
            throw new IllegalArgumentException("Index out of range for two-letter prefix: " + index);
        }
        int firstLetterPos = (int) (index / 26);
        int secondLetterPos = (int) (index % 26);
        return String.valueOf((char) ('A' + firstLetterPos)) + (char) ('A' + secondLetterPos);
    }
}

实体类的ID配置更新

把原来的固定前缀参数替换成新的配置项:

@Id
@GeneratedValue(generator = "user_seq_generator", strategy = GenerationType.SEQUENCE)
@GenericGenerator(
    name = "user_seq_generator",
    strategy = "user.util.UserIdGenerator",
    parameters = {
        @Parameter(name = SequenceStyleGenerator.INCREMENT_PARAM, value = "1"),
        // 设置固定前缀
        @Parameter(name = UserIdGenerator.FIXED_PREFIX_PARAMETER, value = "RxT-"),
        // 设置数字部分的位数(4位)
        @Parameter(name = UserIdGenerator.DIGIT_LENGTH_PARAMETER, value = "4"),
        // 序列初始值设为1,保证第一个ID是RxT-AA0001
        @Parameter(name = SequenceStyleGenerator.INITIAL_PARAM, value = "1")
    }
)
@Column(name = "user_id")
private String id;

扩展说明

  • 如果需要支持三位字母前缀(比如AAA→AAB→...→ZZZ),只需要修改convertIndexToLetters方法,增加对第三位字母的计算逻辑即可。
  • 确保数据库中的序列初始值为1,否则第一个ID可能不符合预期。如果之前已经使用过序列,记得调整序列的当前值,避免ID重复。
  • 字母段的进位逻辑是基于26进制的,完全符合你需要的AA→AB→ZZ的递增规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:17:35