mybatis-plus雪花算法自动生成机器id原理及源码

 更新时间:2021年06月04日 11:51:53   作者:叁滴水  
Mybatis-Plus是一个Mybatis的增强工具,它在Mybatis的基础上做了增强,却不做改变,Mybatis-Plus是为简化开发、提高开发效率而生,但它也提供了一些很有意思的插件,比如SQL性能监控、乐观锁、执行分析等,下面一起看看mybatis-plus雪花算法自动生成机器id原理解析

1、雪花算法原理

        雪花算法使用一个 64 bit 的 long 型的数字作为全局唯一 id。这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。

img

  1. 1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。
  2. 41bit-时间戳,用来记录时间戳,毫秒级。
  3. 10bit-工作机器id,用来记录工作机器id。
  4. 12bit-序列号,序列号,用来记录同毫秒内产生的不同id。即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。

SnowFlake可以保证:

所有生成的id按时间趋势递增
整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

        如上大概了解了雪花算法的原理,而且也知道机器号对于雪花算法的重要性。如果机器号一样,可能会出现id重复的情况。

        mybatis-plus自3.3.0开始,默认使用雪花算法+UUID(不含中划线),但是它并没有强制让开发者配置机器号。这一点很是疑惑,这样可能会让不了解雪花算法的人埋下了一个坑。
        但是这么强大的一个框架难道真的没有做优化吗?带着问题,查看了下mybatis-plus雪花算法源码com.baomidou.mybatisplus.core.toolkit.Sequence。最终发现在没有设置机器号的情况下,会通过当前物理网卡地址和jvm的进程ID自动生成。这真的是一个较好的解决方案。一般在一个集群中,MAC+JVM进程PID一样的几率非常小。

2、自动生成唯一机器号源码

核心代码。有两个构造方法,一个无参构造,一个有参构造。

public Sequence() {
    //通过当前物理网卡地址获取datacenterId
    this.datacenterId = getDatacenterId(maxDatacenterId);
    //物理网卡地址+jvm进程pi获取workerId
    this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}

/**
 * 有参构造器
 *
 * @param workerId     工作机器 ID
 * @param datacenterId 序列号
 */
public Sequence(long workerId, long datacenterId) {
    Assert.isFalse(workerId > maxWorkerId || workerId < 0,
            String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
    Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0,
            String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
    this.workerId = workerId;
    this.datacenterId = datacenterId;
}
  • 无参构造 开发者没有设置机器号时
  • 有参构造 开发者自行设置机器号
protected static long getDatacenterId(long maxDatacenterId) {
    long id = 0L;
    try {
        //获取本机(或者服务器ip地址)
        //DESKTOP-123SDAD/192.168.1.87
        InetAddress ip = InetAddress.getLocalHost();
        NetworkInterface network = NetworkInterface.getByInetAddress(ip);
        //一般不是null会进入else
        if (network == null) {
            id = 1L;
        } else {
            //获取物理网卡地址
            byte[] mac = network.getHardwareAddress();
            if (null != mac) {
                id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
                id = id % (maxDatacenterId + 1);
            }
        }
    } catch (Exception e) {
        logger.warn(" getDatacenterId: " + e.getMessage());
    }
    return id;
}
/**
 * 获取 maxWorkerId
 */
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
    StringBuilder mpid = new StringBuilder();
    mpid.append(datacenterId);
    //获取jvm进程信息
    String name = ManagementFactory.getRuntimeMXBean().getName();
    if (StringUtils.isNotBlank(name)) {
        /*
         * 获取进程PID
         */
        mpid.append(name.split(StringPool.AT)[0]);
    }
    /*
     * MAC + PID 的 hashcode 获取16个低位
     */
    return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}

以上就是mybatis-plus雪花算法自动生成机器id原理的详细内容,更多关于mybatis plus雪花id的资料请关注脚本之家其它相关文章!

相关文章

  • 简单了解Mybatis如何实现SQL防注入

    简单了解Mybatis如何实现SQL防注入

    这篇文章主要介绍了简单了解Mybatis如何实现SQL防注入,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • SpringBoot Test类注入失败的解决

    SpringBoot Test类注入失败的解决

    这篇文章主要介绍了SpringBoot Test类注入失败的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • IDEA启动Springboot报错:无效的目标发行版:17 的解决办法

    IDEA启动Springboot报错:无效的目标发行版:17 的解决办法

    这篇文章主要给大家介绍了IDEA启动Springboot报错:无效的目标发行版:17 的解决办法,文中通过代码示例和图文讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • 老生常谈反射之Class类的使用(必看篇)

    老生常谈反射之Class类的使用(必看篇)

    下面小编就为大家带一篇老生常谈反射之Class类的使用(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • SpringBoot中动态数据源配置与使用详解

    SpringBoot中动态数据源配置与使用详解

    在现代应用中,处理多数据源是常见的需求,在 Spring Boot 中,这样的需求可以通过动态数据源来轻松实现,本篇博客将详细介绍如何在 Spring Boot 中配置和使用动态数据源,并演示如何切换到指定的数据源,需要的朋友可以参考下
    2024-10-10
  • Eclipse常用快捷键大全

    Eclipse常用快捷键大全

    这篇文章主要介绍了Eclipse常用快捷键大全,较为详细的针对eclipse中各种应用中使用快捷键进行了分类总结,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • 项目打包成jar后包无法读取src/main/resources下文件的解决

    项目打包成jar后包无法读取src/main/resources下文件的解决

    本文主要介绍了项目打包成jar后包无法读取src/main/resources下文件的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Spring @Conditional注解示例详细讲解

    Spring @Conditional注解示例详细讲解

    @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean,这篇文章主要介绍了Spring @Conditional注解示例详细讲解,需要的朋友可以参考下
    2022-11-11
  • SpringBoot中进行事务回滚的方法

    SpringBoot中进行事务回滚的方法

    在Spring Boot中,可以使用TransactionTemplate或@Transactional注解来进行事务管理,本文主要介绍了SpringBoot中进行事务回滚的方法,感兴趣的可以了解一下
    2023-11-11
  • 全面了解servlet中cookie的使用方法

    全面了解servlet中cookie的使用方法

    下面小编就为大家带来一篇全面了解servlet中cookie的使用方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06

最新评论