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

Hibernate 6.X如何实现仅当主键为空时生成自增ID?

问题描述

保存新实体时,主键列需要支持两种处理逻辑:

  • 若主键列为空则生成自增ID(Hibernate 5.X中通过@GeneratedValue(strategy = GenerationType.IDENTITY)可实现);
  • 若主键列不为空则直接使用手动设置的ID,不生成自增ID。

在Hibernate 5.X版本中,通过自定义生成器结合注解实现了该需求,实体类主键注解如下:

@Id
@org.springframework.data.annotation.Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "CustomIdGenerator")
@GenericGenerator(name = "CustomIdGenerator", strategy = "com.CustomIdentityGenerator ")
private Long id;

对应的自定义生成器代码:

public class CustomIdentityGenerator 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 != Integer.valueOf(0) ? id : super.generate(session, object);
    }
}

但升级到Hibernate 6.X后,IdentityGenerator类中不再存在原generate方法,尝试多种重写方式均无效,请问在Hibernate 6.X中是否仍可实现该需求?


解决方案

Hibernate 6.X依然可以实现该需求,只是需要适配新版本的标识符生成器API(Hibernate 6重构了这部分体系),以下是两种可行的实现方式:

方式一:继承IdentityGenerator适配新API

Hibernate 6中IdentityGenerator实现了PostInsertIdentifierGenerator接口,重写其generate方法即可:

public class CustomIdentityGenerator extends IdentityGenerator {

    @Override
    public Object generate(SharedSessionContractImplementor session, Object entity) {
        // 获取实体当前的主键值
        IdentifierAccess identifierAccess = session.getEntityPersister(null, entity)
                .getIdentifierDescriptor()
                .getIdentifierAccess(entity);
        Object id = identifierAccess.getCurrentValue();
        
        // 主键非空且不为默认值时直接返回,否则调用父类生成自增ID
        if (id != null && !id.equals(0L)) {
            return id;
        }
        return super.generate(session, entity);
    }
}

实体类注解无需大幅修改,保持原有配置即可:

@Id
@org.springframework.data.annotation.Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "CustomIdGenerator")
@GenericGenerator(name = "CustomIdGenerator", strategy = "com.yourpackage.CustomIdentityGenerator")
private Long id;

方式二:直接实现IdentifierGenerator接口

如果需要更灵活的控制,可直接实现IdentifierGenerator接口,自定义完整逻辑:

public class CustomIdentityGenerator implements IdentifierGenerator {

    @Override
    public Object generate(SharedSessionContractImplementor session, Object entity) throws HibernateException {
        IdentifierAccess identifierAccess = session.getEntityPersister(null, entity)
                .getIdentifierDescriptor()
                .getIdentifierAccess(entity);
        Object id = identifierAccess.getCurrentValue();
        
        if (id != null && !id.equals(0L)) {
            return id;
        }
        
        // 调用Hibernate内置的Identity生成逻辑处理自增场景
        IdentityGenerator identityGenerator = new IdentityGenerator();
        return identityGenerator.generate(session, entity);
    }
}

注意事项

  • 确保@GenericGenerator的strategy属性指向自定义生成器的正确全限定类名;
  • 测试需覆盖「手动设置ID」和「不设置ID」两种场景,验证逻辑符合预期;
  • 需保证Spring Data JPA版本与Hibernate 6.X兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:32:52