netcore中,并发会引起单号重复,请教怎么解决?
公司有一套仓储系统,有多个业务(入库、出库、盘点、采购、批发等),每个业务都有一个单号,这个单号在表中是唯一键,单号的规则是存储在SQLSERVER表中,按日期每天从0001开始生成,比如202206010001这样。
表结构大概是下面这样
业务名 | 日期 | 序号 |
入库 | 20220601 | 1 |
出库 | 20220601 | 5 |
采购 | 20220601 | 3 |
批发 | 20220601 | 999 |
现在系统业务流程是:
业务开始 ->
取单号数据(所有业务的取单号都在一个静态类的静态方法里)
-> 设置序号+1
-> 返回单号
-> 保存业务数据 。
现在出现的问题是,如果客户在同一时间操作同一个业务人数较多,生成的单号就会重复。
我想在取单号数据那个静态方法里面添加lock代码:
private static object _lock=new object(); public static string GetCode(string name,string date){ lock(_lock){ //数据库查询到业务+日期的序号 // 更改序号+1,并保存到数据库 //返回组合的单号(name + date + 序号) } }
但是这样写会有一个问题,就是多个业务他会在同一个线程上取单号,这样如果操作不同业务的人数比较多,那么等待时间会很长。
我想请教下,有没有一种解决方案,能够根据 我的业务和日期,来分开lock取单号。就是每个业务一个线程取单号的。 前提是不硬编码分开写不同业务的取单号?
回答
1,试试引入redis的incr,但要考虑Redis会被清,如果incr后结果是1需要和数据库对比下。也可以开个任务定时检查数据库和redis的差距,如果数据库大就调整redis,如果redis大就更新数据库,最好从运维层次禁止清redis。
2.为了减少访问网络请求,单台机器可以多申请一些,比如incr 1000,未来的1000条都属于这个服务所用,但也可能造成浪费。可以加lock,因为无需访问数据库,应该是不太影响性能的。
3.做好压测,对比下速度是否ok
(引入redis的一个重要原因,如果服务部署多份,单个机器是无法保证唯一的,需要依赖分布式缓存.)