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
相关产品推荐
相关产品推荐

