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

Spring Boot JPA中枚举前缀+数据库生成ID的复合@Id实现问询

实现Spring Boot + JPA 自定义复合字符串ID生成(前缀+序列)

针对你需要生成{固定长度序列值}-{枚举前缀}格式的复合ID需求,提供两种落地方案,均能保证事务内的ID唯一性与完整性:

方案一:自定义Hibernate IdentifierGenerator(推荐)

通过扩展Hibernate的ID生成器,直接集成到JPA的ID生成生命周期中,逻辑更规范且无需手动管理序列调用。

1. 实现自定义ID生成器

import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;

import java.io.Serializable;
import java.util.Properties;

public class CompositePrefixIdGenerator implements IdentifierGenerator {

    private SequenceStyleGenerator sequenceGenerator;

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) {
        // 复用Hibernate内置序列生成器,配置序列参数
        sequenceGenerator = new SequenceStyleGenerator();
        params.setProperty("sequence_name", "my_entity_seq"); // 数据库序列名称
        params.setProperty("initial_value", "1");
        params.setProperty("increment_size", "1");
        sequenceGenerator.configure(type, params, serviceRegistry);
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object obj) {
        if (!(obj instanceof MyEntity entity)) {
            throw new IllegalArgumentException("仅支持MyEntity类型的ID生成");
        }
        // 生成序列值并格式化为5位固定长度字符串
        Long sequenceVal = (Long) sequenceGenerator.generate(session, obj);
        String formattedSeq = String.format("%05d", sequenceVal);
        // 拼接枚举前缀生成最终ID
        return formattedSeq + "-" + entity.getMyEnum().getPrefix();
    }
}

2. 实体类配置

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Enumerated;
import jakarta.persistence.EnumType;
import org.hibernate.annotations.GenericGenerator;

@Entity
public class MyEntity {

    @Id
    @GenericGenerator(
        name = "composite-prefix-generator",
        type = CompositePrefixIdGenerator.class
    )
    @GeneratedValue(generator = "composite-prefix-generator")
    private String compositeId;

    @Enumerated(EnumType.STRING)
    private MyEnum myEnum;

    // 构造器、getter、setter...
    // 注意:保存实体前必须设置myEnum字段,否则生成器会抛出异常
}

方案二:@PrePersist回调结合数据库序列(快速实现)

利用JPA的生命周期回调,手动调用数据库序列生成ID,逻辑更直观。

1. 创建数据库序列

以PostgreSQL为例,执行SQL创建序列:

CREATE SEQUENCE my_entity_seq START WITH 1 INCREMENT BY 1;

2. 实体类配置

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Enumerated;
import jakarta.persistence.EnumType;
import jakarta.persistence.PrePersist;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;

@Entity
public class MyEntity {

    @Id
    private String compositeId;

    @Enumerated(EnumType.STRING)
    private MyEnum myEnum;

    @PersistenceContext
    private EntityManager entityManager;

    @PrePersist
    public void generateCompositeId() {
        // 仅在ID未设置且枚举值存在时生成
        if (compositeId == null && myEnum != null) {
            // 获取序列下一个值
            Long sequenceVal = (Long) entityManager.createNativeQuery("SELECT nextval('my_entity_seq')").getSingleResult();
            String formattedSeq = String.format("%05d", sequenceVal);
            compositeId = formattedSeq + "-" + myEnum.getPrefix();
        }
    }

    // 构造器、getter、setter...
}

关键注意事项

  • 必须提前设置枚举值:两种方案都依赖实体的myEnum字段值,保存前务必赋值,否则会生成失败
  • 唯一性保障:数据库序列本身是线程安全且事务安全的,能保证ID全局唯一
  • 格式调整:%05d控制序列值的固定长度,可根据业务需求修改位数(如%08d生成8位数字)
  • 多序列扩展:若不同枚举类型需要独立序列,可在自定义生成器中根据myEnum动态切换序列名称

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:22:47