[022][数据模块]基于雪花算法的 MyBatis-Plus 主键生成器设计与实现

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 本项目基于Hutool雪花算法,为MyBatis-Plus定制轻量级分布式主键生成器,含`SnowflakeUtils`(单例+JVM参数配置)、`DefaultIdentifierGenerator`(无缝接入MP)及自动配置类,支持全局有序、高性能ID生成,已落地多个微服务系统。(239字)

[022][数据模块]基于雪花算法的 MyBatis-Plus 主键生成器设计与实现

本项目代码:https://gitee.com/yunjiao-source/tutorials4j

1. 背景

在分布式系统中,数据库主键 ID 的生成是一个常见挑战。传统自增主键在分库分表场景下会失效,而 UUID 虽然全局唯一但占用空间大且无序,影响索引性能。雪花算法(Snowflake)由 Twitter 开源,生成 64 位 Long 型 ID,既能保证全局唯一性,又能保持时间有序,成为分布式 ID 的主流方案。

本文介绍一个在实际项目中整合了 Hutool 雪花算法MyBatis-Plus 的完整解决方案,包含三个核心组件:

  • SnowflakeUtils:雪花算法工具类,提供单例封装和系统属性配置。
  • DefaultIdentifierGenerator:实现 MyBatis-Plus 的 IdentifierGenerator 接口,将雪花 ID 接入 MyBatis-Plus。
  • DataMybatisPlusConfiguration:自动配置类,注册拦截器(分页、乐观锁、防全表更新)并设置全局 ID 生成器。

2. 雪花算法工具类:SnowflakeUtils

2.1 设计目标

  • 提供静态方法 nextId()nextIdStr(),方便业务代码调用。
  • 支持通过 JVM 启动参数动态配置 workerIddatacenterId,适应多节点部署。
  • 单例模式避免重复初始化,保证性能。

2.2 核心代码解析

public class SnowflakeUtils {
   
    public static final String WORKER_ID = "TUTORIALS4J_SNOWFLAKE_WORKER_ID";
    public static final String DATACENTER_ID = "TUTORIALS4J_SNOWFLAKE_DATACENTER_ID";

    private Snowflake snowflake;
    private static SnowflakeUtils INSTANCE;

    private SnowflakeUtils() {
   
        initSnowflake();
    }

    private synchronized void initSnowflake() {
   
        if (snowflake != null) return;
        long datacenterId = getLongProperty(DATACENTER_ID, 1);
        long workerId = getLongProperty(WORKER_ID, 1);
        snowflake = IdUtil.getSnowflake(workerId, datacenterId);
    }

    // 双重检查锁单例
    protected static SnowflakeUtils getInstance() {
    ... }

    public static long nextId() {
   
        return getInstance().snowflake.nextId();
    }

    public static String nextIdStr() {
   
        return getInstance().snowflake.nextIdStr();
    }
}
  • 系统属性读取:例如 -DTUTORIALS4J_SNOWFLAKE_WORKER_ID=2,若未配置则默认 1
  • 异常处理:当属性值非数字时抛出 FrameworkRuntimeException,防止静默失败。
  • Hutool 集成:直接复用 IdUtil.getSnowflake(),减少重复造轮子。

2.3 使用示例

// 生成 long 型 ID
long id = SnowflakeUtils.nextId();

// 生成字符串型 ID(内部仍是雪花算法,非 UUID)
String idStr = SnowflakeUtils.nextIdStr();

3. MyBatis-Plus 标识生成器适配:DefaultIdentifierGenerator

MyBatis-Plus 允许通过 IdentifierGenerator 接口自定义主键生成策略。我们的实现非常简单:

public class DefaultIdentifierGenerator implements IdentifierGenerator {
   
    @Override
    public Number nextId(Object entity) {
   
        return SnowflakeUtils.nextId();
    }

    @Override
    public String nextUUID(Object entity) {
   
        return SnowflakeUtils.nextIdStr();
    }
}
  • nextId() 用于 @TableId(type = IdType.ASSIGN_ID) 且字段类型为数值(Long/Integer)的场景。
  • nextUUID() 用于字段类型为字符串的场景,但注意这里生成的是雪花 ID 的字符串形式,并非真正的 UUID,名称上可优化。

4. MyBatis-Plus 自动配置:DataMybatisPlusConfiguration

该配置类的作用是在 Spring Boot 环境中自动装配 MyBatis-Plus 的核心能力。

4.1 全局 ID 生成器配置

@Bean
public MybatisPlusPropertiesCustomizer defaultIdentifierGeneratorMybatisPlusPropertiesCustomizer() {
   
    return plusProperties -> plusProperties.getGlobalConfig()
            .setIdentifierGenerator(new DefaultIdentifierGenerator());
}

这样所有使用 IdType.ASSIGN_ID 的实体都会自动使用雪花算法生成主键,无需在每个实体类上重复配置。

5. 整体工作流程

  1. Spring Boot 启动 → 加载 DataMybatisPlusConfiguration
  2. 配置全局 ID 生成器 → 将 DefaultIdentifierGenerator 设置到 MyBatis-Plus 全局配置中。
  3. 业务插入数据时 → MyBatis-Plus 检测到主键为 ASSIGN_ID 策略 → 调用 DefaultIdentifierGenerator.nextId()SnowflakeUtils.nextId() → 生成全局唯一有序 ID。

6. 部署配置说明

在分布式部署时,需要为每个节点分配唯一的 workerIddatacenterId。推荐通过环境变量或 JVM 参数注入:

java -DTUTORIALS4J_SNOWFLAKE_WORKER_ID=1 \
     -DTUTORIALS4J_SNOWFLAKE_DATACENTER_ID=1 \
     -jar your-app.jar
  • workerId 范围:0~31(Hutool 默认支持 5 bit,可自定义扩展)
  • datacenterId 范围:0~31
  • 确保所有节点组合唯一,否则可能生成重复 ID。

7. 优缺点分析

7.1 优点

  • 全局唯一且有序:雪花 ID 基于时间戳,天然适合作为数据库主键,利于 B+ 树索引。
  • 高性能:本地生成,无网络开销,单机每秒可达百万级。
  • 配置灵活:通过系统属性控制 worker 和 datacenter,适合容器化部署。

7.2 注意事项

  • 时钟回拨问题:Hutool 的 Snowflake 默认会抛出异常,生产环境需确保 NTP 服务配置正确或使用可容忍回拨的变种。
  • workerId 分配:在 Kubernetes 等动态 IP 环境中,需借助外部分发(如 ZooKeeper、Redis)自动分配 workerId。
  • 字符串 ID 命名nextUUID 方法实际生成雪花 ID 的字符串形式,容易引起误解,可重命名为 nextIdStr

8. 扩展与改进建议

  1. 支持时钟回拨容忍:可参考百度 UidGenerator 或美团 Leaf,增加缓冲机制。
  2. 自动注册 workerId:基于 Redis 或 etcd 实现 workerId 动态分配与心跳续期。
  3. 细化配置:允许通过 application.yml 配置 workerId,而非仅系统属性。

9. 总结

本文提供的三个类构成了一套轻量级、可投入生产的分布式主键解决方案。通过合理的工具封装和框架集成,开发者只需引入依赖并配置 JVM 参数,即可享受到雪花算法带来的高性能与全局有序性,同时还能利用 MyBatis-Plus 的拦截器增强数据库操作安全性。

该方案已在多个微服务项目中稳定运行,适用于中大规模分布式系统的主键生成场景。

目录
相关文章
|
2月前
|
运维 Java 开发者
[015][web模块]基于Spring Boot的HTTP客户端日志与默认配置实战
本文详解基于Spring Boot的HTTP客户端统一配置方案,支持RestTemplate、RestClient与WebClient三种客户端,实现无侵入的日志记录(请求/响应头、状态码)、默认请求头注入(如X-Request-Id)、非2xx异常自动转换及链路追踪支持,全部通过Customizer与Filter机制自动装配,开箱即用,提升微服务调用可观测性与开发效率。(239字)
240 5
[015][web模块]基于Spring Boot的HTTP客户端日志与默认配置实战
|
2月前
|
缓存 安全 搜索推荐
[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器
本文介绍Spring Boot中Caffeine缓存的灵活定制方案:通过自定义`FlexibleCaffeineCacheManager`,支持按缓存名(如users/products)独立配置过期策略、容量等参数,兼顾全局默认与个性化需求;结合线程安全创建器、属性合并机制及无缝Spring集成,实现高性能、易扩展、零侵入的本地缓存管理。(239字)
154 2
|
2月前
|
缓存 NoSQL Java
[006][缓存模块] 两级缓存实战:基于 Caffeine + Redis 的多级缓存设计与实现
本文介绍基于Caffeine(本地)+ Redis(分布式)的两级缓存实战方案,通过自定义`MultiLevelCache`与`MultiLevelCacheManager`,实现Spring Cache标准接口下的透明多级缓存:读优先本地(纳秒级)、未命中查Redis并回填;写同步更新两级,兼顾高性能与数据共享。代码开源可直接集成。
235 0
|
2月前
|
缓存 NoSQL 算法
【Redis】Redis——过期键删除策略、内存淘汰8种策略、LRU/LFU实现
Redis过期删除与内存淘汰是两大核心内存管理机制:前者按TTL自动清理失效键(惰性+定期组合),后者在`maxmemory`超限时主动淘汰键(8种策略,含LRU/LFU近似实现)。二者目标、触发条件与作用范围截然不同,需精准区分与配置。
|
21小时前
|
设计模式 缓存 安全
[043][数据模块]基于 Spring Data JPA 的企业级数据访问层设计——实体、审计、状态与服务抽象
本项目基于Spring Data JPA构建企业级数据访问层,通过分层接口(Entity/IdEntity/AuditingEntity/StatusEntity)与抽象基类(BaseEntity/BaseService),统一处理主键生成、乐观锁、审计字段、数据状态及CRUD逻辑,显著减少样板代码,提升可维护性与复用性。(239字)
33 1
|
2月前
|
缓存 NoSQL 安全
[013][缓存模块]基于Redis的计数器缓存模板设计——AbstractCounterCacheTemplate 技术解析
`AbstractCounterCacheTemplate` 是基于 Redis 的轻量级计数器缓存模板,支持原子计数、阈值校验与自动溢出异常(如登录/短信频控)。键可选 MD5 加密,开箱即用,线程安全,适用于分布式限流场景。(239字)
91 1
[013][缓存模块]基于Redis的计数器缓存模板设计——AbstractCounterCacheTemplate 技术解析
|
2月前
|
缓存 NoSQL Java
[012][缓存模块]基于 Spring Cache 的缓存操作模版,支持Caffeine缓存, Redis缓存及两级缓存
本项目基于Spring Cache抽象,提供Caffeine本地缓存、Redis分布式缓存及两级缓存(Caffeine+Redis)的统一操作模板。通过工厂模式与模板方法,封装get/put/delete/异步加载等能力,支持租户隔离、类型安全与Spring生命周期集成,显著简化缓存接入。(239字)
121 3
[012][缓存模块]基于 Spring Cache 的缓存操作模版,支持Caffeine缓存, Redis缓存及两级缓存
|
2月前
|
缓存 运维 Java
[014][web模块]构建可重复读取的请求体:Spring Boot 请求缓存过滤器设计与实现
本文介绍Spring Boot中实现可重复读取请求体的缓存过滤器方案,通过`HttpServletRequestWrapper`包装、内存缓存与条件过滤,解决流式请求体只能读一次的痛点,支持日志、验签等多场景复用,具备自动配置、长度限制、路径匹配等特性,轻量透明,开箱即用。(239字)
118 1
|
2月前
|
算法 Java 数据库连接
[011][数据模块]基于雪花算法的 Hibernate 分布式主键生成器设计与实现
本文介绍基于雪花算法的Hibernate分布式主键生成器,支持`@SnowflakeIDGenerator`注解一键集成,自动适配String/Long类型主键,具备全局唯一、趋势递增、高性能等优势,适用于分库分表与微服务场景。(239字)
200 4
|
2月前
|
缓存 druid Java
[010][数据模块]多数据源管理器在 Hibernate 多租户中的应用
本文介绍基于`DataSourceRoutingManager`的Hibernate数据库级多租户方案:通过动态路由与连接池模板复制(支持HikariCP/DBCP2/Druid),实现租户专属数据源的懒加载、缓存与无缝集成,配置简洁、扩展性强,已落地多个SaaS生产项目。(239字)
124 2

热门文章

最新文章