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

如何在Spring Boot与Hibernate中使用随机唯一数值作为主键?

实现Spring Boot + MySQL 随机唯一数值主键(非UUID、自增类型)

JPA/Hibernate没有直接提供随机数值类型的主键生成器,但可以通过两种实用方式实现需求:

方案一:自定义Hibernate主键生成器

通过实现Hibernate的IdentifierGenerator接口,自定义生成逻辑,确保生成的数值唯一且符合需求:

  1. 编写自定义生成器类
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import java.security.SecureRandom;

public class RandomNumericIdGenerator implements IdentifierGenerator {
    private static final SecureRandom RANDOM = new SecureRandom();
    // 定义数值范围,比如10位数字,降低重复概率
    private static final long MIN = 1000000000L;
    private static final long MAX = 9999999999L;

    @Override
    public Object generate(SharedSessionContractImplementor session, Object object) {
        // 生成随机数,循环校验确保数据库中不存在
        long id = MIN + ((long) (RANDOM.nextDouble() * (MAX - MIN)));
        while (isIdExists(session, object.getClass(), id)) {
            id = MIN + ((long) (RANDOM.nextDouble() * (MAX - MIN)));
        }
        return id;
    }

    private boolean isIdExists(SharedSessionContractImplementor session, Class<?> entityClass, long id) {
        return session.createQuery("select count(e) from " + entityClass.getSimpleName() + " e where e.id = :id")
                .setParameter("id", id)
                .uniqueResult() != 0L;
    }
}
  1. 在实体类中绑定生成器
import jakarta.persistence.*;
import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "target_table")
public class TargetEntity {
    @Id
    @GenericGenerator(name = "random_numeric_id", strategy = "com.your.package.RandomNumericIdGenerator")
    @GeneratedValue(generator = "random_numeric_id")
    @Column(name = "id", nullable = false, unique = true)
    private Long id;

    // 其他字段、getter/setter
}

方案二:手动生成主键(简单场景推荐)

在业务层手动生成随机数值,设置到实体后再保存,依赖数据库唯一约束兜底保障唯一性:

  1. 实体类主键配置(关闭自动生成)
import jakarta.persistence.*;

@Entity
@Table(name = "target_table")
public class TargetEntity {
    @Id
    @Column(name = "id", nullable = false, unique = true)
    private Long id;

    // 其他字段、getter/setter
}
  1. 业务层生成唯一ID并保存
import org.springframework.stereotype.Service;
import java.security.SecureRandom;

@Service
public class TargetEntityService {
    private static final SecureRandom RANDOM = new SecureRandom();
    private static final long MIN = 1000000000L;
    private static final long MAX = 9999999999L;

    private final TargetEntityRepository repository;

    public TargetEntityService(TargetEntityRepository repository) {
        this.repository = repository;
    }

    public TargetEntity saveEntity(TargetEntity entity) {
        Long uniqueId = generateUniqueId();
        entity.setId(uniqueId);
        return repository.save(entity);
    }

    private Long generateUniqueId() {
        Long id;
        do {
            id = MIN + ((long) (RANDOM.nextDouble() * (MAX - MIN)));
        } while (repository.existsById(id));
        return id;
    }
}

关键注意事项

  • 字段类型:MySQL侧用BIGINT存储主键,避免数值溢出
  • 唯一性兜底:必须给主键字段添加UNIQUE约束,即使代码层做了校验,也能在极端场景拦截重复插入
  • 性能优化:如果数据量极大,可改用Redis缓存已使用的ID,减少数据库查询次数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:37:20