栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

.NetCore两种生成雪花Id的方式~

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.NetCore两种生成雪花Id的方式~

在阅读本教程之前,你需要知道: 在Net5中生成雪花Id有两种方法 第一种,使用Yitter.IdGenerator+Helper, 另外一种则使用纯手写Helper

  1. 下面先介绍第一种 使用Yitter.IdGenerator+Helper的方法

1.首先 选择需要添加雪花Id的项目,右键,选择Yitter.IdGenerator,下载

 

2.创建一个名为 YitIdHelper的类

 

  1. 给类里面写入代码

public class YitIdHelper

    {

        static YitIdHelper()

        {

            var options = new IdGeneratorOptions(1); //构造方法初始化雪花Id

            YitIdHelper.SetIdGenerator(options);

        }

        private static IIdGenerator _IdGenInstance = null;

        public static IIdGenerator IdGenInstance => _IdGenInstance;

        /// 

        /// 设置参数,建议程序初始化时执行一次

        /// 

        /// 

        public static void SetIdGenerator(IdGeneratorOptions options)

        {

            _IdGenInstance = new DefaultIdGenerator(options);

        }

        /// 

        /// 生成新的Id

        /// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。

        /// 否则将会初始化一个WorkerId为1的对象。

        /// 

        /// 

        public static long NextId()

        {

            if (_IdGenInstance == null)

            {

                _IdGenInstance = new DefaultIdGenerator(

                    new IdGeneratorOptions() { WorkerId = 0 }

                    );

            }

            return _IdGenInstance.NewLong();

        }

}

注意,控制器在调用NextId()方法生成雪花Id之前需要先New SetIdGenerator(IdGeneratorOptions options)方法给SetIdGenerator传参,但是此处改进过

static YitIdHelper()

        {

            var options = new IdGeneratorOptions(1); //构造方法初始化雪花Id

            YitIdHelper.SetIdGenerator(options);

        }

该构造方法直接在初始化YitIdHelper 类的时候就已将参数‘1’传入public static void SetIdGenerator(IdGeneratorOptions options) 方法完成初始化

故 控制器调用时则不需要再对该类进行处理

控制器调用如图

 

这样就生成了一个使用Yitter.IdGenerator+Helper方法生成的雪花Id啦!

  1. 使用纯手写Heper的方法生成雪花Id

纯手写的方法生成雪花Id在控制器里面调用时有两种方法

  1. 注入方法注入
  2. 控制器里面New方法传参

先介绍控制器里面New的方法 首先在API里面创建一个类 命名为IdWorker

 

然后写入以下代码

public class IdWorker

    {

        //机器ID

        private static long workerId;

        private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳

        private static long sequence = 0L;

        private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)

        public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID

        private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码

        private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数

        private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数

        public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成

        private long lastTimestamp = -1L;

        /// 

        /// 机器码

        /// 

        /// 

        public IdWorker(long workerId)

        {

            if (workerId > maxWorkerId || workerId < 0)

                throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", workerId));

            IdWorker.workerId = workerId;

        }

        public long nextId()

        {

            lock (this)  // 锁

            {

                long timestamp = timeGen();

                if (this.lastTimestamp == timestamp)

                { //同一微秒中生成ID

                    IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限

                    if (IdWorker.sequence == 0)

                    {

                        //一微秒内产生的ID计数已达上限,等待下一微妙

                        timestamp = tillNextMillis(this.lastTimestamp);

                    }

                }

                else

                { //不同微秒生成ID

                    IdWorker.sequence = 0; //计数清0

                }

                if (timestamp < lastTimestamp)

                { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过

                    throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",

                        this.lastTimestamp - timestamp));

                }

                this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳

                long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;

                return nextId;

            }

        }

        /// 

        /// 获取下一微秒时间戳

        /// 

        /// 

        /// 

        private long tillNextMillis(long lastTimestamp)

        {

            long timestamp = timeGen();

            while (timestamp <= lastTimestamp)

            {

                timestamp = timeGen();

            }

            return timestamp;

        }

        /// 

        /// 生成当前时间戳

        /// 

        /// 

        private long timeGen()

        {

            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;

        }

    }

之后 在控制器里面调用

 

注意 在生成雪花Id的类中有一个方法 必须在NextI()方法前传参初始化 如下图

 

所以在控制器里面调用生成雪花Id的NextId方法前必须

IdWorker idWorker = new IdWorker(1);

之后再idWorker.nextId();就可以得到雪花Id啦!

下面开始进阶 介绍控制器注入的方法

先阐述一下使用构造函数注入遇到的问题

 

在构造函数注入的时候 无法象new一样初始化IdWorker

所以 需要对IdWorker类进行特殊处理

 

首先 在IdWorker类里面注入‘配置’类,使用 配置类的GetSection方法获取appsetting.json文件里面的‘Id’值 也就是初始化 雪花Id生成类需要传入的参数

 

然后在控制器里注入

 

注入前,别忘了使用typeof关键字在StartUp里面注册IdWorker类哦~

services.AddScoped(typeof(IdWorker));

使用注入的属性

IdWorker.nextId();就可以生成雪花Id啦~

完结 撒花~~~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995493.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号