SQL Server悲观锁和乐观锁

1、什么悲观锁是?

在同一时间内只允许一个线程更新数据 ,在查询的时候锁住查询出来的结果集,如果没有加聚集索引那么会锁定整张表,锁定期间可以新增和查询数据。

go
CREATE TABLE T
(
    t_id int,
    t_name nvarchar(1024),
    t_count int,
    t_version int
)
go
insert into t(t_id,t_name,t_count,t_version ) values(1,'a',10000,0)
insert into t(t_id,t_name,t_count,t_version ) values(2,'b',10000,0)
declare @count as int = 0
begin tran
    select @count=t_count  from t WITH(UPDLOCK) where t_id = 1 
    WAITFOR DELAY '0:0:05' --延迟5秒
    update t set t_count=@count-1 where t_id = 1
commit TRAN

2、什么是乐观锁?

乐观锁和悲观锁的概念相反。通常是用version字段来实现。

declare @count as int = 0
declare @v int = 0
begin tran
    select @count=t_count,@v=t_version  from t where t_id = 1 
    WAITFOR DELAY '0:0:05' --延迟5秒
    update t set t_count=@count-1,t_version = t_version + 1 where t_id = 1 and t_version = @v
commit TRAN

3、什么时候用悲观锁?什么时候用乐观锁?

选择使用那一种锁取决于访问频率和一旦产生冲突的严重性。如果系统被并发访问的概率很低,或者冲突发生后的后果不太严重(所谓后果指被检测到冲突的提交会失败,必须重来一次),可以使用乐观锁,否则使用悲观锁。

例如有个修改用户姓名的场景,有线程A、B。

乐观锁:如果在A线程事务提交之前B线程修改了用户姓名,那么A线程会修改失败。修改失败后可能会给用户 “xxx 失败”的提示,然后刷新当前数据,数据展示为B线程修改后的数据,那么此时用户可能就会有疑问明明修改失败了,怎么还是修改了?刚刚还叫张三的呢,现在怎么变成李四了?如果可以接受这种情况,那么就可以使用乐观锁反之使用悲观锁。

悲观锁:A线程先将要修改的数据加锁,在A线程事务还没提交之前,B线程是不能修改的。

悲观锁类似避免冲突,乐观锁类似解决冲突。

4、其他扩展

锁有两种分类方法。
(1) 从数据库系统的角度来看锁分为以下三种类型:

  • 独占锁(Exclusive Lock)
    独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT、 UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁。但当对象上有其它锁存在时,无法对其加独占锁。独占锁一直到事务结束才能被释放。
  • 共享锁(Shared Lock)
    共享锁锁定的资源可以被其它用户读取,但其它用户不能修改它。在SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定。通常加共享锁的数据页被读取完毕后,共享锁就会立即被释放。
  • 更新锁(Update Lock)
    更新锁是为了防止死锁而设立的。当SQL Server 准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server 确定要进行更新数据操作时,它会自动将更新锁换为独占锁。但当对象上有其它锁存在时,无法对其作更新锁锁定。

(2)从程序员的角度看
锁分为以下两种类型:

  • 乐观锁(Optimistic Lock)
  • 悲观锁(Pessimistic Lock)

参考文章

https://www.cnblogs.com/knowledgesea/p/3714417.html

https://blog.csdn.net/sd4015700/article/details/50162965?locationNum=9

https://www.cnblogs.com/sunshch/archive/2013/04/02/2994781.html

猜你喜欢

转载自blog.csdn.net/qq_32109957/article/details/106837773