当前位置:首页 > EF Core > 正文内容

数据存储主键类的选择-雪花漂移算法

sharpdog1个月前 (11-03)EF Core73

数据存储主键类的选择-雪花漂移算法

常用主键类型:

  • 整型:int,long。优点:可以自增,占用空间小,存取速度快。缺点:难于扩展,需要合并、分表、分库或者数据迁移会相当痛苦。不大适合分布式存储。

  • 字符串。性能差不推荐使用。

  • GUID/UUID:优点:全局唯一,合并、分表、分库,迁移相当方便。缺点:无序,存储存储空间大,性能差,每次新增数据会导致索引重新排序。

从上可以看出整型和GUID/UUID的优缺点正好相反。

想要一种同时具有整型和GUID/UUID的优点的主键,可以参考Twitter公开的雪花算法(Snowflake),Twitter原版https://github.com/twitter-archive/snowflake,网上有很多国内写的实现,如:https://github.com/cloudyan/snowflake。生成一个 64 bit 的整数,保证不同进程主键的不重复性以及相同进程主键的有序性。

优点:生成的 ID 都是趋势递增的;不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也是非常高的;根据自身业务特性分配 bit 位,非常灵活

缺点:强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。

个人更喜欢用国人写的雪花漂移https://github.com/yitter/IdGenerator,优点巴拉巴拉介绍了一大堆,主要用起来简单。

在.Net项目中用法如下:

1、NuGet包管理器中添加IdGenerator包引用

image-20231103154003837.png

2、在程序初始化时配置工作站编号。

打开项目的Program.cs文件,添加以下代码。

// 配置雪花漂移算法
var options = new IdGeneratorOptions(1);
YitIdHelper.SetIdGenerator(options);`

其中“IdGeneratorOptions(1)”中的数字“1”是机器码,不同的系统使用不同的机器码避免生成的id重复,默认最大值为63,可以配置64个系统。通过配置WorkerIdBitLength参数增加机器码长度。

3、在模型类中生成id。

新建模型类:Entity

类中的Id属性添加Key, DatabaseGenerated(DatabaseGeneratedOption.None)标注,表示Id为主键且生成行为不进行任何处理,也就不自增。并在Entity类的构造函数中使用YitIdHelper.NextId()生成id。代码如下

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Yitter.IdGenerator;

namespace Ledger.Entity
{
   /// <summary>
   /// 保存到数据库的根实体。
   /// </summary>
   public class Entity
   {
       /// <summary>
       /// 构造函数
       /// </summary>
       /// <param name="createNewId">创建新ID</param>
       public Entity(bool createNewId)
       {
           if(createNewId) Id = YitIdHelper.NextId();
       }
       public Entity(long id)
       {
           Id = id;
       }

       [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
       public long Id {  get; set; }

       /// <summary>
       /// 为Id创建一个新值
       /// </summary>
       public void CreateNewId()
       {
           Id = YitIdHelper.NextId();
       }
   }
}

为避免每次实例化时都自动创建Id影响性能,这里有两个构造函数:

  • public Entity(bool createNewId),明确传入createNewId=true时才创建id。主要用于实例化一个需要保存到数据库的新对象时采用。

  • public Entity(long id),传入一个Id值,用在非创建新对象时用。

另外还写了一个public void CreateNewId()方法,在需要时为类生成新id。

为了使用方面Entity可以做基类,其他模型类继承自这个类。

如:

using System.ComponentModel.DataAnnotations;

namespace Ledger.Entity
{
   /// <summary>
   /// 商户
   /// </summary>
   public class Shop : Entity
   {
       /// <summary>
       /// 创建新商户
       /// </summary>
       /// <param name="bookId">账本Id</param>
       /// <param name="name">名称</param>
       /// <param name="createNewId">是否创建新id</param>
       public Shop(long bookId, string name,bool createNewId = true) : base(createNewId)
       {
           BookId = bookId;
           Name = name;
       }
       /// <summary>
       /// 设置已有商户
       /// </summary>
       /// <param name="id">商户Id</param>
       /// <param name="bookId">账本Id</param>
       /// <param name="name">名称</param>
       public Shop(long id,long bookId, string name) : base(id)
       {
           BookId = bookId;
           Name = name;
       }

       /// <summary>
       /// 图标
       /// </summary>
       public string? Icon {  get; set; }
       /// <summary>
       /// 名称
       /// </summary>
       [StringLength(20)]
       public string Name { get; set; }
   }
}

其他没有什么不同。


扫描二维码推送至手机访问。

版权声明:本文由洞庭夕照发布,如需转载请注明出处。

本文链接:http://ninesky.cn/?id=5

分享给朋友:
返回列表

没有更早的文章了...

没有最新的文章了...

相关文章

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。