事务与锁应用实战之手工生成流水号

事务与锁应用实战之手工生成流水号

作者:no_mIss

对于编号,通常我们会使用自动编号,但有时也会生成诸如BH0001之类的编号?
方法一般是查询表中最大的值,然后将这个值加1即得到新的编号。

这里我们不讨完全在一个表的例子,我们为了更好的扩展性,
单独建一个表,来放maxid,其原理是相同的。


首先建个表,为了生成不同项目的最大ID号
CREATE TABLE T_table(id int ,projectid char(1) PRIMARY KEY)
INSERT INTO T_table SELECT 1,'A'
INSERT INTO T_table SELECT 1,'B'
INSERT INTO T_table SELECT 1,'C'

注:A、B、C代表不同的项目,在这里我们只用A
本篇假定是为了生成订单号OrderId。


接下来创建一个存储过程,来返回订单号OrderId

CREATE PROC P_CreateOrderId       
    @ProjectId CHAR(1),--项目名称
    @reOrderId VARCHAR(50) OUTPUT--返回的订单号
AS
BEGIN TRAN
    DECLARE @maxid int
    --取projectid为A的最大id
    SELECT @maxid = (id+1) FROM T_table WHERE projectid = @ProjectId
    --这里我们显示的设置下延时10s钟
    WAITFOR DELAY '00:00:10'
    UPDATE T_table SET id = @maxid FROM T_table WHERE projectid = @ProjectId
    SELECT @reOrderId = @maxid    
COMMIT TRAN

调用方法:
declare @reOrderId int
exec P_CreateOrderId 'A',@reOrderId out
select @reOrderId

得到这个Orderid后,你可以再对其格式化了,比如BH00001之类。

初看这个你可能觉得没有任何问题,但如果你做过多用户并发存取数据的项目,你会发现一个问题:
如果两个用户同时执行
SELECT @maxid = (id+1) FROM T_table WHERE projectid = @ProjectId
的话,那么就会取到相同的值@maxid.这显然是不可以接受的。


为了更明显的说明问题,我加了这一句:
WAITFOR DELAY '00:00:10'


当我们执行
declare @reOrderId int
exec P_CreateOrderId 'A',@reOrderId out
select @reOrderId
时,我们同时再另一个进程里执行
select * from T_table where projectid='A'
发现,可以取到当前表里projectid为A的数据,显然说明当多个用户同时执行这个PROC时,
都取到了同一个(maxid+1)做为返回的订单ID。



呵呵。。。。。说点别的。。。。

我们知道MSSQL所有对数据的操作都是先放置锁,再操作的。
当SELECT时,放置共享锁,而共享锁执行完就释放,所以当SELECT完后,
其它的用户仍然可以再放置共享锁,所以我们只要让SELECT完后不释放,直到
其所在的事务完全释放后再释放共享锁就可以了。


好了,到这里目标很明确了。?

让我们来提高事务的隔离等级:
将这句SELECT @maxid = (id+1) FROM T_table WHERE projectid = @ProjectId
改成:SELECT @maxid = (id+1) FROM T_table(XLOCK,PAGLOCK) WHERE projectid = @ProjectId

说明:
XLOCK 使用排它锁并一直保持到由语句处理的所有数据上的事务结束时。使用PAGLOCK或TABLOCK指定该锁。


如此设置后,当一个用户执行该存储过程时,其它的用户需要排下队等下了。
顺便说一声:像这种事务越短越好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值