浅谈 SQL 中的锁(六)查看锁的基本方法

像前面的例子  http://bibaoke.com/post/29  那样,阻塞事务的语句是必须的:

--延长处理时间
waitfor delay '0:00:10'


这个语句代表在查询中等待 10秒,这样我们才能模拟并发的情况,如果事务很快执行完毕了,就无法重现并发的情况。

我在网上看到有些例子是使用 C#、Java 等语言启动多个线程去模拟并发,而不是使用阻塞,虽然这样更接近生产环境,但并不利于简化问题。多个线程模拟并发,取决于线程数和事务执行的速度,难以确认并发发生了,而且编码量稍多。

然后是使用 sys.dm_tran_locks 视图去查看锁:

--查看 id 54 的会话持有的锁
select * from sys.dm_tran_locks 
where request_session_id = 54

如果在指定的会话是活动的,没有任何正在执行的事务,可以看一个数据库的共享锁:


这大概是防止在数据库有活动会话时,对数据库进行一些影响数据一致性的更改的。

在 id 54 的会话中,使用  http://bibaoke.com/post/25  例子中的 app_user 表,执行下面的语句:

--开始事务  
begin transaction  

--查询指定用户
select * from app_user(updlock) 
where mobile = '13800002222'

--延长处理时间  
waitfor delay '0:00:10'  

--提交事务  
commit transaction  


在 10秒内,查看锁:


可以看到会话多持有了三个锁,一个页面意向更新锁,一个键更新锁,一个对象意向排它锁,锁的范围和类型问题比较复杂,而且不同的数据库产品的实现细节不同,对这个有兴趣的可以搜索相关的内容。

有趣的一点是,如果上面这个语句不使用 updlock 表提示,是看不到加锁的情况的。原因是在 read committed 默认的隔离级别下,select 语句放置的共享锁是不会一直持有到事务结束的。repeatable read 和 serializable 的共享锁则会一直持有到事务结束。

使用这个方法,就可以看到在不同隔离级别下,使用不同的表提示,数据库的加锁情况。

粤ICP备15047625号-2