- 下面先介绍第一种 使用Yitter.IdGenerator+Helper的方法
1.首先 选择需要添加雪花Id的项目,右键,选择Yitter.IdGenerator,下载
2.创建一个名为 YitIdHelper的类
- 给类里面写入代码
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啦!
- 使用纯手写Heper的方法生成雪花Id
纯手写的方法生成雪花Id在控制器里面调用时有两种方法
- 注入方法注入
- 控制器里面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啦~
完结 撒花~~~



