流水编号

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

  1. 工作流的流水编号

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

  1. 采购订单号

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

  1. XX业务受理单编号

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

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

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

怎样开启编号规则

  //如果需要使用编号那么一定要开启此功能
HiSql.Global.SnroOn = true; //开启编号后进行初始化
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 编号长度 StartNum 和EndNum 的长度 两者的长度要一至否则会报错
IsNumber 是否纯数字编号 当为true 编号按0-9的10进制数字编号,当为false时按0-9 A-Z 36进度数字和字母混合编号
IsHasPre 是否有前辍 可以按到年月日时分秒作为前辍 在PreType 配置
PreType 前辍编号类型 详细请见 PreType 前置编号类型配置
FixPreChar 固定前辍 固定一个字符串 每个生成的码前面都加上这个值
PreChar 当前前辍 不需要配置 在编号的过程中会将 FixPreChar 和 PreType 存在此昝
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 的配置可以自行做个配置界面进行配置,以下是通过程序进行配置保存.

  List<Hi_Snro> list = new List<Hi_Snro>();

  ///工作流编号配置
///按天产生流水号 如2205061000000-2205069999999 之间 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 = "工作流编号" }); ///生成销售订单编码 每分钟从0开始编号 如20220602145800001-20220602145899999
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 = "销售订单号流水" });
///生成另外一种销售订单编码 年的是取后两位 按每秒顺序生成 如22060214581200001-22060214581299999
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 = "销售订单号流水" }); ///通过雪花ID生成
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" }); //保存配置到表中
sqlClient.Modi("Hi_Snro", list).ExecCommand();

编号生成代码环境配置

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

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

设置连接

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

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

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

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

编号测试

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


SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO CREATE TABLE [dbo].[H_nlog](
[Nid] [int] IDENTITY(1,1) NOT NULL,
[Numbers] [varchar](50) NULL,
[CreateTime] [datetime] NULL,
[CreateName] [nvarchar](50) NULL,
[ModiTime] [datetime] NULL,
[ModiName] [nvarchar](50) NULL,
CONSTRAINT [PK_H_nlog] PRIMARY KEY CLUSTERED
(
[Nid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateTime] DEFAULT (getdate()) FOR [CreateTime]
GO ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateName] DEFAULT ('') FOR [CreateName]
GO ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiTime] DEFAULT (getdate()) FOR [ModiTime]
GO ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiName] DEFAULT ('') FOR [ModiName]
GO 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'
GO 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'
GO 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'
GO 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'
GO

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

  List<object> lst = new List<object>();
for (int i = 0; i < 1000; i++)
{
var num = number.NewNumber("WFNO", 1);
lst.Add(new { Numbers = num });
Console.WriteLine(num);
} 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. 【uniapp 开发】智能温控开关 (环状图)

    index.vue <template> <view> <view class="qiun-columns"> <uCharts id=& ...

  2. 每天找回一点点之MD5加密算法

    之前在做项目的时候用户密码都进行了MD5的加密,今天突然想起来了总结一下(●'◡'●) 一.MD5是什么? MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被 ...

  3. C++---变量、数据类型和运算符

    内存 计算机使用内存来记忆或存储计算时所使用的的数据. 计算机执行程序时, 组成程序的指令和程序所操作的数据都必须存放在某个地方, 而这个地方就是计算机的内存, 也称为主存, 或随机访问存储器(RAM ...

  4. 超星尔雅看课刷题小tips

    用chrom浏览器,先安装扩展程序Tampermonkey BETA 然后进入> https://greasyfork.org/zh-CN 找一款适合自己的脚本安装即可刷课.

  5. 深入理解Kafka核心设计及原理(二):生产者

    转载请注明出处: 2.1Kafka生产者客户端架构 2.2 Kafka 进行消息生产发送代码示例及ProducerRecord对象 kafka进行消息生产发送代码示例: public class Ka ...

  6. MySql创建分区

    一.Mysql分区类型 1.RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区. 2.HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列 ...

  7. Java-GUI编程之处理位图

    如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调 . AWT 也允许在组件上绘制位图, Graphics 提供了 drawlmage() 方法用于绘制位图,该方法需要一个Image参数一一代 ...

  8. 邮件html页编写指南

    前言 写过邮件的html一般都用table来布局,为什么呢?原因是大多数的邮件客户端(比如Outlook和Gmail),会过滤经过多次的邮件编写实践及度娘的指导,我发现,编写自制兼容outlook与f ...

  9. DevOps转型到底值不值?

    摘要:企业进行DevOps转型是否有价值?是否能计算出明确的投资回报率呢?本文将为您解惑. 本文分享自华为云社区<DevOps转型到底值不值?>,作者:敏捷小智 . 引言 企业都是以盈利为 ...

  10. Apache Doris 通过ODBC连接SQL Server

    社区有小伙伴有使用Doris ODBC外表连接SQL Server数据库,使用中遇到不知道驱动怎么安装,苦于我这边也没有SQL Server的环境,正好社区有用户使用了这个数据库,也安装ODBC驱动测 ...