流水编号

日常在我们开发的过程中可能会用到编号的功能,如销售订单号,采购订单号,日志编号,凭证号...等等,为了保证唯一有些表的主键要么用自增长,要么用GUID值,或通过雪花ID算法生成。这此方式基本都能产生唯一的ID,但如果在分布式环境下产生流水ID,以上这几种方式可能就不太好用,如有以下场景

  1. 工作流的流水编号

工作流的编号通常会是以下格式 如2022060200001-2022060299999 到了第二天时尾数又要生00001开始编,这种编号规则有一个好处就是非常直观的通过工作流编号就可以看出来这是哪一天申请的流程,一天大概有多少流水码。那么如果我们用常规编号规则其实是比较难完成此需求的。

  1. 采购订单号

如在实际业务需求中 标准采购订单要用5000000000-5999999999 这个号进行进行编码,委外采购订单用4000000000-4999999999号段进行编码

  1. XX业务受理单编号

在办里某业务时根据业务类型使用不同的编号 如财务收款用的流水号是 SK10000000-SK99999999,支出用的是ZC10000000-ZC99999999

根据以上的业务场景如果使用常规的编号是比较难实现的(要保证分布式环境编号不重复且按流水编码),那么HiSql 提供了比较方便的解决方案

该版本还未正式更新nuget 需要使用请下载源码

怎样开启编号规则

  1. //如果需要使用编号那么一定要开启此功能
  2. HiSql.Global.SnroOn = true;
  3. //开启编号后进行初始化
  4. sqlClient.CodeFirst.InstallHisql();//仅需执行一次 如果使用的低版本的HiSql 升级引用包手需要重新初始化安装

初始安装完成后会生成表Hi_Snro 这个编号配置表

编号配置介绍

Hi_Snro 表详细说明

字段 描述 备注
SNRO 编号规则名称 主键 字符串(10)
SNUM 子编号 主键 整数
IsSnow 是否雪花ID bool true:表示雪花id false:表示自定义流水编号
SnowTick 雪花ID时间戳 int64 IsSnow 为true时配置 大于0 都可以,其它的都可以不用配置
StartNum 编号开始值 字符串(20) 当IsNumber 为true 时编号只能纯数字 为false时 可以以0-9 A-Z 混编
EndNum 编号结束值 字符串(20) 当编号超过此时时将会抛出异常号段池已满
CurrNum 当前编号值 字符串(20) 第一次配置时值要等于StartNum
CurrAllNum 当前完整编号 字符串(40) 不需要配置,产生流水时会自动生成
Length 编号长度 StartNumEndNum 的长度 两者的长度要一至否则会报错
IsNumber 是否纯数字编号 当为true 编号按0-9的10进制数字编号,当为false时按0-9 A-Z 36进度数字和字母混合编号
IsHasPre 是否有前辍 可以按到年月日时分秒作为前辍 在PreType 配置
PreType 前辍编号类型 详细请见 PreType 前置编号类型配置
FixPreChar 固定前辍 固定一个字符串 每个生成的码前面都加上这个值
PreChar 当前前辍 不需要配置 在编号的过程中会将 FixPreCharPreType 存在此昝
CacheSpace 号段缓存 编号使用越频繁这个值配置越大 常的建议配置为10 值越大编号性能越好
CurrCacheSpace 当前缓存池使用的数量 不需要配置
Descript 编号描述 备注一下当前编号规则

PreType 前置编号类型配置

PreType 是一个枚举类

字段 备注
PreType.None 0 表示无前置
PreType.Y 1 表示前置为日期格式[yyyy] 即当前年份如2022
PreType.Y2 12 表示前置为日期格式[yy] 即当前年份后两位如22
PreType.YM 2 表示前置为日期格式[yyyyMM] 即当前年月如202206
PreType.Y2M 22 表示前置为日期格式[yyMM] 即当前年月如2206
PreType.YMD 3 表示前置为日期格式[yyyyMMdd] 即当前年月日如20220602
PreType.Y2MD 32 表示前置为日期格式[yyMMdd] 即当前年月日如220602
PreType.YMDH 4 表示前置为日期格式[yyyyMMddHH] 即当前年月日时如2022060216
PreType.Y2MDH 42 表示前置为日期格式[yyMMddHH] 即当前年月日时如22060216
PreType.YMDHm 5 表示前置为日期格式[yyyyMMddHHmm] 即当前年月日时分如202206021630
PreType.Y2MDHm 52 表示前置为日期格式[yyMMddHHmm] 即当前年月日时分如2206021630
PreType.YMDHms 6 表示前置为日期格式[yyyyMMddHHmmss] 即当前年月日时分秒如20220602163020
PreType.Y2MDHms 62 表示前置为日期格式[yyMMddHHmmss] 即当前年月日时分秒如220602163020

根据以上配置规则将数据配置到表中

配置样例

Hi_Snro 的配置可以自行做个配置界面进行配置,以下是通过程序进行配置保存.

  1. List<Hi_Snro> list = new List<Hi_Snro>();
  2. ///工作流编号配置
  3. ///按天产生流水号 如2205061000000-2205069999999 之间
  4. list.Add( new Hi_Snro { SNRO = "WFNO", SNUM = 1, IsSnow = false, SnowTick = 0, StartNum = "1000000", EndNum = "9999999", Length = 7, CurrNum = "1000000", IsNumber = true, PreType=PreType.Y2MD, FixPreChar="", IsHasPre = true, CacheSpace = 5, Descript = "工作流编号" });
  5. ///生成销售订单编码 每分钟从0开始编号 如20220602145800001-20220602145899999
  6. list.Add(new Hi_Snro{ SNRO = "SALENO", SNUM = 1, IsSnow = false, SnowTick = 0, StartNum = "10000", EndNum = "99999", Length = 5, CurrNum = "10000", IsNumber = true, PreType = PreType.YMDHm, FixPreChar = "", IsHasPre = true, CacheSpace = 10, Descript = "销售订单号流水" });
  7. ///生成另外一种销售订单编码 年的是取后两位 按每秒顺序生成 如22060214581200001-22060214581299999
  8. list.Add(new Hi_Snro { SNRO = "SALENO", SNUM = 2, IsSnow = false, SnowTick = 0, StartNum = "10000", EndNum = "99999", Length = 5, CurrNum = "10000", IsNumber = true, PreType = PreType.Y2MDHms, FixPreChar = "", IsHasPre = true, CacheSpace = 10, Descript = "销售订单号流水" });
  9. ///通过雪花ID生成
  10. list.Add( new Hi_Snro { SNRO = "Order", SNUM = 1, IsSnow=true, SnowTick=145444, StartNum = "", EndNum = "",Length=7, CurrNum = "", IsNumber = true, IsHasPre = false, CacheSpace = 10, Descript = "订单号雪花ID" });
  11. //保存配置到表中
  12. sqlClient.Modi("Hi_Snro", list).ExecCommand();

编号生成代码环境配置

建议把SeriNumber 做成一个局静态变量

  1. public static SeriNumber number = null; //定义个全局变更的流水号对象

设置连接

  1. //sqlClient 为数据库连接对象
  2. number = new SeriNumber(sqlClient);

如果应用进行了分布式布署 请一定要启用以下代码

  1. HiSql.Global.RedisOn = true;//开启redis缓存
  2. HiSql.Global.RedisOptions = new RedisOptions { Host = "172.16.80.178", PassWord = "qwe123", Port = 6379, CacheRegion = "HRM", Database = 2 };
  3. HiSql.Global.NumberOptions.MultiMode= true;
  4. //如果部署了分布式且也要生成雪花ID 一定要配置以下当前应用的ID 多个应用间只要不重复即可0-31之间
  5. HiSql.Global.NumberOptions.WorkId=1;

通过以上配置则分布式编号环境配置完成,下面就可以进行编号测试了

编号测试

为了测试编号是否有重复我这里建了一个测试记录表H_nlog ,编号生成完成后可以分析该表的数据看是否有重复数据,(测试环境 为SqlServer) sql代码如下


  1. SET ANSI_NULLS ON
  2. GO
  3. SET QUOTED_IDENTIFIER ON
  4. GO
  5. CREATE TABLE [dbo].[H_nlog](
  6. [Nid] [int] IDENTITY(1,1) NOT NULL,
  7. [Numbers] [varchar](50) NULL,
  8. [CreateTime] [datetime] NULL,
  9. [CreateName] [nvarchar](50) NULL,
  10. [ModiTime] [datetime] NULL,
  11. [ModiName] [nvarchar](50) NULL,
  12. CONSTRAINT [PK_H_nlog] PRIMARY KEY CLUSTERED
  13. (
  14. [Nid] ASC
  15. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  16. ) ON [PRIMARY]
  17. GO
  18. ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateTime] DEFAULT (getdate()) FOR [CreateTime]
  19. GO
  20. ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateName] DEFAULT ('') FOR [CreateName]
  21. GO
  22. ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiTime] DEFAULT (getdate()) FOR [ModiTime]
  23. GO
  24. ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiName] DEFAULT ('') FOR [ModiName]
  25. GO
  26. EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'CreateTime'
  27. GO
  28. EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'CreateName'
  29. GO
  30. EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'ModiTime'
  31. GO
  32. EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'ModiName'
  33. GO

根据编号规则WFNO 子编号1 生成编号

  1. List<object> lst = new List<object>();
  2. for (int i = 0; i < 1000; i++)
  3. {
  4. var num = number.NewNumber("WFNO", 1);
  5. lst.Add(new { Numbers = num });
  6. Console.WriteLine(num);
  7. }
  8. sqlClient.Insert("H_nlog", lst).ExecCommand();

测试结果

启用了分布式多个应用同时对同一个编号规则产生编号不会产生重复编号。

怎样生成分布式的流水ID的更多相关文章

  1. 框架篇:分布式全局唯一ID

    前言 每一次HTTP请求,数据库的事务的执行,我们追踪代码执行的过程中,需要一个唯一值和这些业务操作相关联,对于单机的系统,可以用数据库的自增ID或者时间戳加一个在本机递增值,即可实现唯一值.但在分布 ...

  2. Zookeeper命名服务——生成分布式有序且唯一id

    生成分布式有序且唯一id的方法有很多种,使用zookeeper是比较简单的一种方法,只是生成的速度不高,这里只是一个借助zk的版本号生成分布式唯一且有序id的例子. ZkIdGenerator.jav ...

  3. 数据库分库分表(一)常见分布式主键ID生成策略

    主键生成策略 系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,下面介绍一些常见的ID生成策略. Sequence ID UUID GUID COMB Snowflake 最开始的自增ID为了实 ...

  4. 全局流水ID号生成的几种方法

    这个问题源自于,我想找一个分布式下的ID生成器.  这个最简单的方案是,数据库自增ID.为啥不用咧?有这么几点原因,一是,会依赖于数据库的具体实现,比如,mysql有自增,oracle没有,得用序列, ...

  5. redis生成分布式id方案

    分布式Id - redis方式   本篇分享内容是关于生成分布式Id的其中之一方案,除了redis方案之外还有如:数据库,雪花算法,mogodb(object_id也是数据库)等方案,对于redis来 ...

  6. (4.24)【mysql、sql server】分布式全局唯一ID生成方案

    参考:分布式全局唯一ID生成方案:https://blog.csdn.net/linzhiqiang0316/article/details/80425437 分表生成唯一ID方案 sql serve ...

  7. 分布式全局唯一ID生成策略

    为什么分布式系统需要用到ID生成系统 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店.猫眼电影等产品的系统中,数据日渐增长,对数据库的分库分表后需要有 ...

  8. 常见分布式全局唯一ID生成策略

    全局唯一的 ID 几乎是所有系统都会遇到的刚需.这个 id 在搜索, 存储数据, 加快检索速度 等等很多方面都有着重要的意义.工业上有多种策略来获取这个全局唯一的id,针对常见的几种场景,我在这里进行 ...

  9. 分库分表的 9种分布式主键ID 生成方案,挺全乎的

    <sharding-jdbc 分库分表的 4种分片策略> 中我们介绍了 sharding-jdbc 4种分片策略的使用场景,可以满足基础的分片功能开发,这篇我们来看看分库分表后,应该如何为 ...

随机推荐

  1. 微信小程序和公众号和H5之间相互跳转

    参考链接:https://www.imooc.com/article/22900 一.小程序和公众号 答案是:可以相互关联. 在微信公众号里可以添加小程序. 可关联已有的小程序或快速创建小程序.已关联 ...

  2. 使用vue-cli构建工具构建vue项目时候组件的使用

    <template> <div class="contains"> <!-- <div class="main"> & ...

  3. 接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理)

    接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理) 1.抽象类 以下说辞可能不太准确,但是会让你醍醐灌顶 抽象类是把一些具有共同属性(包括行为)的东西抽象出来,比如: 小狗有身高,体重,颜 ...

  4. Java 在Word指定段落/文本位置插入分页符

    在Word插入分页符可以在指定段落后插入,也可以在特定文本位置处插入.本文,将以Java代码来操作以上两种文档分页需求.下面是详细方法及步骤. [程序环境] 在程序中导入jar,如下两种方法: 方法1 ...

  5. Mysql学习day2随笔

    --jion on 连接查询 --jion where 等值查询 建议先用jion on再用where过滤 --inner jion 返回交集 --left join 无论右表是否匹配,都会从左表返回 ...

  6. Java学习day24

    今天学习了IP地址.端口以及TCP/UDP通信协议 网络连接与过去的信件类似,需要知道对方的地址才能寄出去,在计算机网络中,我们的地址就是IP以及端口号 IP能用来唯一定位一台联网的计算机 本机的IP ...

  7. Vuecli版本调整

    1.当前版本号查看 1.Windows+R打开命令提示符2.输入cmd3.vue --version或者vue -V(大写V) 2.版本操作 安装指定版本 情况一:目前处于3.0及以上 版本查看和卸载 ...

  8. java高级用法之:在JNA中使用类型映射

    目录 简介 类型映射的本质 TypeMapper NativeMapped 总结 简介 JNA中有很多种映射,library的映射,函数的映射还有函数参数和返回值的映射,libary和函数的映射比较简 ...

  9. 比 Navicat 还要好用、功能更强大的工具!

    DBeaver 是一个基于 Java 开发,免费开源的通用数据库管理和开发工具,使用非常友好的 ASL 协议.可以通过官方网站或者 Github 进行下载. 由于 DBeaver 基于 Java 开发 ...

  10. 【面试普通人VS高手系列】Spring Boot中自动装配机制的原理

    最近一个粉丝说,他面试了4个公司,有三个公司问他:"Spring Boot 中自动装配机制的原理" 他回答了,感觉没回答错误,但是怎么就没给offer呢? 对于这个问题,看看普通人 ...