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

如何在Hibernate中实现可复用的通用自定义ID生成器

如何在Hibernate中实现可复用的通用自定义ID生成器

我太懂你想要的效果了——就是能在不同实体类里靠一个简单注解,比如@CustomId(name = "USR"),自动生成带指定前缀的唯一ID,不用每个实体都重复写生成逻辑对吧?其实Hibernate本身就提供了扩展点来实现这个需求,我来一步步拆解说清楚:

第一步:定义你的自定义@CustomId注解

首先得把这个注解“造”出来,还要用Hibernate的@IdGeneratorType把它和后面要写的生成器绑定在一起,这样Hibernate才知道这个注解要对应哪个生成逻辑:

import org.hibernate.annotations.IdGeneratorType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;

// 标记这个注解只能用在字段上
@Target(FIELD)
// 让注解在运行时能被Hibernate读取到
@Retention(RetentionPolicy.RUNTIME)
// 绑定后面要实现的生成器类
@IdGeneratorType(CustomPrefixIdGenerator.class)
public @interface CustomId {
    // 用来指定ID的前缀,比如"USR"、"ORD"
    String name();
    
    // 可选参数:指定用哪个数据库序列生成数字部分,默认用global_id_seq
    String sequenceName() default "global_id_seq";
}

第二步:实现自定义ID生成器类

接下来就是核心的生成逻辑了,我们要写一个类实现Hibernate的IdentifierGenerator接口,把前缀和自增数字拼接起来。这里我用数据库序列来保证数字部分的唯一性,这样生成的ID既带前缀又不会重复:

import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.persister.entity.EntityPersister;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Properties;

public class CustomPrefixIdGenerator implements IdentifierGenerator {

    // 复用Hibernate自带的序列生成器来处理数字自增部分
    private SequenceStyleGenerator sequenceGenerator;

    @Override
    public void configure(org.hibernate.type.Type type, Properties params, org.hibernate.service.ServiceRegistry serviceRegistry) throws org.hibernate.id.IdentifierGeneratorException {
        // 初始化序列生成器,不用自己写自增逻辑
        sequenceGenerator = new SequenceStyleGenerator();
        sequenceGenerator.configure(type, params, serviceRegistry);
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object entity) throws org.hibernate.HibernateException {
        try {
            // 获取当前实体的元数据,找到ID字段的名字(不一定叫id哦)
            EntityPersister persister = session.getEntityPersister(null, entity);
            String idFieldName = persister.getIdentifierPropertyName();
            
            // 反射获取ID字段上的@CustomId注解
            Field idField = entity.getClass().getDeclaredField(idFieldName);
            idField.setAccessible(true);
            CustomId customId = idField.getAnnotation(CustomId.class);

            if (customId == null) {
                throw new IllegalArgumentException("实体类的ID字段必须标记@CustomId注解");
            }

            // 从注解里拿到指定的前缀
            String prefix = customId.name();
            // 用序列生成器拿到自增的唯一数字
            Long sequenceValue = (Long) sequenceGenerator.generate(session, entity);
            
            // 格式化成你要的样式,比如USR000001,补零长度可以自己调整
            return String.format("%s%06d", prefix, sequenceValue);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new org.hibernate.HibernateException("生成自定义ID失败", e);
        }
    }
}

第三步:在实体类里愉快复用

现在就可以在各个实体类里轻松使用这个注解了,完全不用重复写生成逻辑:

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    @CustomId(name = "USR", sequenceName = "user_id_seq") // 指定专属序列
    private String id;

    // 其他字段、getter、setter...
}

@Entity
public class Order {
    @Id
    @CustomId(name = "ORD") // 用默认的global_id_seq序列
    private String id;

    // 其他字段、getter、setter...
}

一些要注意的小细节

  • 数据库里要提前创建对应的序列,比如global_id_seq、user_id_seq,如果你的Hibernate配置了hbm2ddl.auto=create或者update,Hibernate会自动帮你创建序列(前提是数据库支持序列,比如PostgreSQL、Oracle)。
  • 要是不想用数据库序列,也可以换成UUID生成唯一部分,比如把sequenceValue换成UUID.randomUUID().toString().substring(0, 8),不过这样ID就没有自增的顺序性了,看业务需求选择就行。
  • 要是需要更复杂的格式,比如前缀+日期+数字,只需要在generate方法里修改拼接逻辑,非常灵活。

这样一套下来,你就有了一个完全可复用的自定义ID生成器,每个实体类加个@CustomId注解就能搞定,完美符合你的需求!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:38:07