Spring Boot 3迁移至Hibernate 6时,替换自定义ID生成逻辑的正确方案咨询
Spring Boot 3迁移至Hibernate 6时,替换自定义ID生成逻辑的正确方案咨询
嘿,我刚好研究过Hibernate 6的ID生成器变化,你的问题很典型——Spring Boot3升级后,原来继承IdentityGenerator的自定义生成器确实失效了,咱们来一步步搞定它:
首先得搞清楚为啥原来的代码用不了:Hibernate 6彻底重构了ID生成器的体系,原来的IdentityGenerator不再是可以直接继承重写generate方法的类,而且新的IdentifierGenerator是个接口,根本没有super.generate()这种方法可以调用。
要实现「如果ID已存在就用,不存在则自动生成」的逻辑,正确的做法是自定义生成器内部委托Hibernate内置的Identity生成器,具体代码如下:
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.factory.spi.GeneratorCreationContext; import org.hibernate.type.Type; import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import java.util.Properties; public class UseIdOrGenerate implements IdentifierGenerator { // 内置的Identity生成器,用来处理需要自动生成ID的场景 private IdentifierGenerator delegateGenerator; @Override public void initialize(Type type, Properties properties, GeneratorCreationContext context) { // 初始化委托生成器,复用Hibernate原生的Identity生成逻辑 this.delegateGenerator = new IdentityGenerator(); this.delegateGenerator.initialize(type, properties, context); } @Override public Object generate(SharedSessionContractImplementor session, Object entity) { BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(entity); Object currentId = beanWrapper.getPropertyValue("id"); // 如果已有ID,直接返回;否则调用委托生成器生成新ID if (currentId != null) { return currentId; } else { return delegateGenerator.generate(session, entity); } } }
接下来在实体类里配置这个生成器就行,注意注解的写法要适配Spring Boot3(用jakarta.persistence替代旧的javax.persistence):
import jakarta.persistence.*; @Entity public class YourEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "useIdOrGenerate") @GenericGenerator(name = "useIdOrGenerate", type = UseIdOrGenerate.class) private Long id; // 其他字段和方法... }
另外给你提个小建议:如果你的需求只是个别实体需要这种逻辑,其实也可以不用自定义生成器——直接给ID字段加上@GeneratedValue(strategy = GenerationType.IDENTITY),然后在保存前手动判断ID是否为空,为空则让Hibernate自动生成,不为空就用传入的ID,这种方式更轻量。
备注:内容来源于stack exchange,提问作者Isvoran Andrei
相关产品推荐
相关产品推荐

