基于 Hibernate 6 自定义字段生成器

298 阅读1分钟

前提

@GeneratedValue(strategy = GenerationType.UUID) 默认会覆盖自己设定的值,导致自己主动设置的字段被重新覆盖

方案一 @PrePersist 声明周期内修改方式。

@PrePersist
protected void onCreate() {
    if (this.id == null) {
       this.id = Objects.requireNonNullElseGet(this.objectId, () -> IdUtil.fastUUID().toLowerCase(Locale.ROOT));
    }
}

方案二 自定义字段生成规则

当前代码仅适用于 Hibernate 6 以上,新版本中已经弃用了 UUIDGenerator 之类的实现需要采用新的实现。

OverflowUUIDGenerator.java
import cn.hutool.core.util.IdUtil;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.EventType;
import org.hibernate.id.IdentityGenerator;

import java.util.Objects;

public class OverflowUUIDGenerator extends IdentityGenerator implements BeforeExecutionGenerator {

    private static Object getId(Object entity, SharedSessionContractImplementor session) {
       return session.getEntityPersister(null, entity).getIdentifier(entity, session);
    }

    @Override
    public Object generate(SharedSessionContractImplementor session, Object entity, Object currentValue,
          EventType eventType) {
       // 尝试获取现有的 ID
       Object id = getId(entity, session);

       // 如果 ID 为空,则生成一个新的 UUID
       if (Objects.isNull(id)) {
          id = IdUtil.randomUUID().toLowerCase();
          // 设置生成的 ID 回到实体中
          session.getEntityPersister(null, entity).setIdentifier(entity, id, session);
       }

       return id;
    }

    @Override
    public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
       Object id = getId(entity, session);
       return Objects.isNull(id) || id instanceof String && ((String) id).isEmpty();
    }

    @Override
    public boolean generatedOnExecution() {
       return true;
    }
}
ColumnOverflowUUIDGenerator.java
import org.hibernate.annotations.IdGeneratorType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD })
@IdGeneratorType(OverflowUUIDGenerator.class)
public @interface ColumnOverflowUUIDGenerator {

}
使用方式
@Id
@ColumnOverflowUUIDGenerator
@Column(name = "id", nullable = false)
private String id;