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

Hibernate 6:自定义ID生成器与内置生成器结合实现方案

Hibernate 6自定义ID生成器:指定ID则复用,否则用MySQL自增

环境配置:MySQL 5.7、Hibernate 6.4.4、Spring Boot 3.2.2

在Hibernate 5中,我用以下类实现了"指定ID则用该值,否则用自增ID"的逻辑:

public class UseExistingIdOtherwiseGenerateUsingIdentity extends IdentityGenerator {

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
        return id != null ? id : super.generate(session, object);
    }
}

迁移到Hibernate 6后这个类直接失效——因为IdentityGenerator不再提供generate方法。尝试改用IdentifierGenerator却出现主键重复问题,需要重新实现符合需求的自定义生成器。

解决方案

在Hibernate 6中,我们需要实现IdentifierGenerator接口,同时结合IdentityGenerator的底层逻辑来处理自增场景,核心思路还是先检查实体是否已有ID,有则直接返回,无则触发MySQL自增:

import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.ServiceRegistry;

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

public class UseExistingIdOtherwiseGenerateUsingIdentity implements IdentifierGenerator {

    private IdentityGenerator identityGenerator;

    @Override
    public void initialize(org.hibernate.metamodel.mapping.IdentifierMapping identifierMapping, Properties properties, ServiceRegistry serviceRegistry) {
        // 初始化内置IdentityGenerator,复用其自增逻辑
        this.identityGenerator = new IdentityGenerator();
        this.identityGenerator.initialize(identifierMapping, properties, serviceRegistry);
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object entity) {
        // 获取实体当前的ID值
        org.hibernate.metamodel.mapping.IdentifierMapping identifierMapping = 
            session.getEntityDescriptor(entity.getClass()).getIdentifierMapping();
        Serializable id = (Serializable) identifierMapping.getIdentifierGetter().get(entity);
        
        if (id != null) {
            // 已有ID,直接返回
            return id;
        }
        // 无ID,调用IdentityGenerator触发MySQL自增
        return identityGenerator.generate(session, entity);
    }
}

使用方式

在实体类的ID字段上配置自定义生成器:

import jakarta.persistence.*;

@Entity
public class YourEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "use-existing-or-identity")
    @GenericGenerator(
            name = "use-existing-or-identity",
            type = UseExistingIdOtherwiseGenerateUsingIdentity.class
    )
    private Long id;

    // 其他字段和方法
}

关键说明

  1. 通过initialize方法初始化内置的IdentityGenerator,直接复用Hibernate对MySQL自增的成熟处理逻辑,避免手动实现自增导致的主键重复问题
  2. 通过IdentifierMapping获取实体ID值,这是Hibernate 6推荐的标识符操作方式,替代了旧版本的ClassMetadata
  3. 优先使用实体已有的ID值,无ID时触发自增,完全适配需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:16:05