sql server对并发的处理-乐观锁和悲观锁

sql server对并发的处理-乐观锁和悲观锁

假如两个线程同时修改数据库同一条记录,就会导致后一条记录覆盖前一条,从而引发一些问题。

例如:

  一个售票系统有一个余票数,客户端每调用一次出票方法,余票数就减一。

情景: 

  总共300张票,假设两个售票点,恰好在同一时间出票,它们做的操作都是先查询余票数,然后减一。

一般的sql语句:

  

1
2
3
4
5
6
7
8
9
declare  @ count  as  int
 
begin  tran
     select  @ count = count  from  ttt
     WAITFOR DELAY  '00:00:05'  --模拟并发,故意延迟5秒
     update  ttt  set  count =@ count -1
commit  TRAN
 
SELECT  FROM  ttt

  

  问题就在于,同一时间获取的余票都为300,每个售票点都做了一次更新为299的操作,导致余票少了1,而实际出了两张票。

  打开两个查询窗口,分别快速运行以上代码即可看到效果。

 

定义解释:

  悲观锁:相信并发是绝大部分的,并且每一个线程都必须要达到目的的。

  乐观锁:相信并发是极少数的,假设运气不好遇到了,就放弃并返回信息告诉它再次尝试。因为它是极少数发生的。

 

悲观锁解决方案:

  

1
2
3
4
5
6
7
declare  @ count  as  int
 
begin  tran
     select  @ count = count  from  tb  WITH (UPDLOCK)
   WAITFOR DELAY  '00:00:05'  --模拟并发,故意延迟5秒
     update  tb  set  count =@ count -1
commit  tran

  

  在查询的时候加了一个更新锁,保证自查询起直到事务结束不会被其他事务读取修改,避免产生脏数据。

  从而可以解决上述问题。

 

乐观锁解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
--首先给表加一列timestamp
 
ALTER  TABLE  ttt  ADD  timesFlag  TIMESTAMP  NOT  null
 
然后更新时判断这个值是否被修改
declare  @ count  as  int
DECLARE  @flag  AS  TIMESTAMP
DECLARE  @rowCount  AS  int
begin  tran
     select  @ count = COUNT ,@flag=timesflag  from  ttt
     WAITFOR DELAY  '00:00:05'
     update  ttt  set  count =@ count -1  WHERE  timesflag=@flag  --这里加了条件
     SET  @rowcount=@@ROWCOUNT   --获取被修改的行数
commit  TRAN
 
--对行数进行判断即可
 
IF @rowCount=1
     PRINT  '更新成功'
ELSE
     PRINT  '更新失败'

  这便是乐观锁的解决方案,可以解决并发带来的数据错误问题,但不保证每一次调用更新都成功,可能会返回'更新失败'

 

悲观锁和乐观锁

  悲观锁一定成功,但在并发量特别大的时候会造成很长堵塞甚至超时,仅适合小并发的情况。

  乐观锁不一定每次都修改成功,但能充分利用系统的并发处理机制,在大并发量的时候效率要高很多。

 

分类:  SqlServer
1
0
« 上一篇: Find、FindAll、Where的区别
» 下一篇: 论MVC中的传值

posted on 2014-09-04 14:07 Tracy.Net 阅读(3772) 评论(3编辑 收藏

评论

#1楼   

果断的沙发~~
2014-09-04 14:40 |  Neal Caffrey   

#2楼   

问题就在于,同一时间获取的余票都为300,每个售票点都做了一次更新为299的操作,导致余票少了1,而实际出了两张票。


这话有点问题吧

假如这三个用户同时到达update这里,这个时候update更新语句会把并发串行化,后者覆盖前者。 所以并不会出现你说的这种情况。
但会出现另外一种问题就是 多个窗口打开都显示 10张余票, 其中8张卖了,但是 仍然显示10张, 此时购买超过2张 就会提示 余票不足。
2017-06-01 21:03 |  Allen_Chang   

#3楼[楼主]   

@ Allen_Chang
这取决于你的新值是在程序里给的还是通过update set val=val-1
2017-06-14 12:05 |  Tracy.Net   
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值