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; // 其他字段和方法 }
关键说明
- 通过
initialize方法初始化内置的IdentityGenerator,直接复用Hibernate对MySQL自增的成熟处理逻辑,避免手动实现自增导致的主键重复问题 - 通过
IdentifierMapping获取实体ID值,这是Hibernate 6推荐的标识符操作方式,替代了旧版本的ClassMetadata - 优先使用实体已有的ID值,无ID时触发自增,完全适配需求
内容的提问来源于stack exchange,提问作者Hemant Singh
相关产品推荐
相关产品推荐

