太原网站关键词推广,金色财经网站开发,网站建设的3个阶段,建筑工程培训有哪些业务背景在管理系统中#xff0c;很多功能模块都会涉及到各种类型的编号#xff0c;例如#xff1a;流程编号、订单号、合同编号等等。编号各有各自的规则#xff0c;但通常有一个流水号来确定编号的唯一性#xff0c;保证流水号的唯一#xff0c;在不同的环境中实现方式… 业务背景在管理系统中很多功能模块都会涉及到各种类型的编号例如流程编号、订单号、合同编号等等。编号各有各自的规则但通常有一个流水号来确定编号的唯一性保证流水号的唯一在不同的环境中实现方式有所不同。本文将介绍在单机和分布式环境中保证流水号唯一的方式。实现思路1、在数据库中创建 seqno 表每个业务一条数据存储业务 code 和流水号的最大值环境dotNET Core2.1VS For Mac2019Docker18.09.2MySql8.0.17基于Docker构建Redis3.2基于Docker构建CSRedisCore3.1.5准备工作1、执行下面命令构建 Redis 容器docker run -p 6379:6379 -d --name s2redis_test --restartalways redis:3.2 redis-server --appendonly yes
2、执行下面命令构建 MySql 容器docker run -d -p 3306:3306 -e MYSQL_USERoec2003 -e MYSQL_PASSWORD123456 -e MYSQL_ROOT_PASSWORD123456 --name s2mysql mysql/mysql-server --character-set-serverutf8mb4 --collation-serverutf8mb4_general_ci --default-authentication-pluginmysql_native_password
3、在 MySql 中创建数据库seqno_test执行下面 SQL 创建表和测试数据-- ----------------------------
-- Table structure for seqno
-- ----------------------------
DROP TABLE IF EXISTS seqno;
CREATE TABLE seqno (code varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,num int(11) DEFAULT NULL
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci;-- ----------------------------
-- Records of seqno
-- ----------------------------
BEGIN;
INSERT INTO seqno VALUES (order, 1);
COMMIT;SET FOREIGN_KEY_CHECKS 1;
4、在 VS2019 中创建两个控制台项目和一个类库项目如下图单机测试1、在 SeqNo 类中添加 GetSeqByNoLock 方法public static string GetSeqNoByNoLock()
{string connectionStr server localhost; user id oec2003; password 123456; database seqno_test;string getSeqNosql select num from seqno where codeorder;string updateSeqNoSql update seqno set numnum1 where codeorder;var seqNo MySQLHelper.ExecuteScalar(connectionStr, System.Data.CommandType.Text, getSeqNosql);MySQLHelper.ExecuteNonQuery(connectionStr, System.Data.CommandType.Text, updateSeqNoSql);return seqNo.ToString();
}
2、在 RedisLockConsoleApp1 控制台程序中用多线程来模拟测试class Program
{static void Main(string[] args){Task.Run(() {for (int i 0; i 50; i){Console.WriteLine($Thread1:SeqNo:{SeqNo.GetSeqNoByNoLock()});}});Task.Run(() {for (int i 0; i 50; i){Console.WriteLine($Thread2:SeqNo:{SeqNo.GetSeqNoByNoLock()});}});Console.ReadLine();}
}
3、测试结果如下可以看出在多线程情况下会出现重复的编号单机环境加锁测试在 SeqNo 类中添加 GetSeqNoByLock 方法通过 Monitor.Enter 来解决单机多线程流水号重复问题public static string GetSeqNoByLock()
{string connectionStr server localhost; user id oec2003; password 123456; database seqno_test;string getSeqNosql select num from seqno where codeorder;string updateSeqNoSql update seqno set numnum1 where codeorder;var seqNo string.Empty;try{Monitor.Enter(_myLock);seqNo MySQLHelper.ExecuteScalar(connectionStr, System.Data.CommandType.Text, getSeqNosql).ToString();MySQLHelper.ExecuteNonQuery(connectionStr, System.Data.CommandType.Text, updateSeqNoSql);Monitor.Exit(_myLock);}catch{Monitor.Exit(_myLock);}return seqNo.ToString();
}
运行结果如下可以看出已经没有出现重复的流水号了多机环境测试Monitor 只能解决进程内的重复性问题现在用两个控制台程序来模拟分布式下的多机器运行在 RedisLockConsoleApp2 控制台程序添加如下代码static void Main(string[] args)
{Task.Run(() {for (int i 0; i 50; i){Console.WriteLine($Thread1:SeqNo:{SeqNo.GetSeqNoByLock()});}});Task.Run(() {for (int i 0; i 50; i){Console.WriteLine($Thread2:SeqNo:{SeqNo.GetSeqNoByLock()});}});Console.ReadLine();
}
同时运行两个控制台程序测试结果如下可以看出在每一个控制台程序内没有重复流水号但两个控制台还是会间歇性地出现重复流水号。要解决这个问题就必须使用分布式锁。多机环境分布式锁测试分布式锁又很多实现方式本例中采用 Redis 来实现Redis 客户端使用的是 CSRedisCore 在 CSRedisCore 最新的版本 3.1.5 中实现了分布式锁这让使用变得非常的方便。1、在 RedisLockLib 项目中添加 CSRedisCore 包的引用2、在 SeqNo 类中添加 GetSeqNoByRedisLock 方法public static string GetSeqNoByRedisLock()
{string connectionStr server localhost; user id oec2003; password 123456; database seqno_test;string getSeqNosql select num from seqno where codeorder;string updateSeqNoSql update seqno set numnum1 where codeorder;var seqNostring.Empty;using (_redisClient.Lock(test, 5000)){seqNo MySQLHelper.ExecuteScalar(connectionStr, System.Data.CommandType.Text, getSeqNosql).ToString();MySQLHelper.ExecuteNonQuery(connectionStr, System.Data.CommandType.Text, updateSeqNoSql);}return seqNo;
}
3、测试结果如下总结例子非常简单提供一种解决问题的思路如您有更好的方式欢迎讨论。本文的示例代码已上传 Github 地址如下https://github.com/oec2003/StudySamples/tree/master/RedisLockDemo祝大家假期快乐