动手分析SQL Server中的事务中使用的锁( 二 )

由于Select语句在SQL Server的默认事务隔离级别(read commited)中执行完成后就会释放相关的锁,而非等到事务结束,在这种情况下无法通过sp_lock或者sys.dm_tran_locks视图观察select语句执行过程中锁的执行情况,因此比较方便的办法是在查询语句执行之前调整当前会话的事务隔离级别为repeatable read,在这个隔离级别中select语句默认会在事故执行完成后提交,比较方便分析 。
在SQL Server Manager Studio的查询窗口中执行语句:
set transaction isolation level repeatable readset statistics profile on begin transelect * from usertable whereid='5E4B68B0-71B8-43FB-B6B4-8E9D43A30589'在前面的事务目前是已经执行未提交的状态,此时可以通过dm_tran_locks查询到该语句目前持有的锁:
select request_session_id,resource_type,request_status,request_mode,resource_description,case resource_typewhen 'Page' then OBJECT_NAME(p.object_id)when 'object' then OBJECT_NAME(lock.resource_associated_entity_id)when 'database' then (select name from master..SysDatabases where dbid=resource_database_id)when 'key' then object_name(p.object_id)end as objectName from sys.dm_tran_locks lockleft join sys.partitions p on p.hobt_id=lock.resource_associated_entity_idorder by lock.request_session_id request_session_id
resource_type
request_status
request_mode
resource_description
objectName
62
DATABASE
GRANT
S
 
Test
62
PAGE
GRANT
IS
0.236111111
UserTable
62
OBJECT
GRANT
IS
 
UserTable
62
KEY
GRANT
S
(0ee48b5e6942)
UserTable
查询结果字段说明:

  • request_session_id:会话编号
  • resource_type:被锁定的资源类型
  • request_status:请求的状态
  • request_mode:锁类型
  • resource_description 资源描述情况
  • objectName:对象名称
目前select查询持有的锁:
  1. 通过目前的查询结果可以看到在DATABASE上加了S锁(数据库名为Test);
  2. 在数据所属的页上增加了意向共享锁;
  3. 表上增加了意向共享锁;
  4. 数据行上增加了共享锁;
目前的事务执行过程中只对于匹配到的数据行进行了锁定,如果插入删除语句并未涉及到该数据行就不会受到影响,但是如果涉及到这行数据那肯定需要等S锁释放后才能进行 。
SQL Server执行insert时使用的锁首先在事务中执行insert语句并且不提交(注意将上个章节中的事务提交):
begin traninsert into UserTable (id,code,name,createtime,lastmodifytime)values(newid(),'test2','测试用户2',getdate(),getdate())insert的时候默认会有事务,因此主动声明一个事务并只执行不提交就可以很容易地查到当前会话持有的锁 。
通过dm_tran_locks查询到该语句目前持有的锁:
request_session_id
resource_type
request_status
request_mode
resource_description
objectName
70
DATABASE
GRANT
S
 
Test
70
PAGE
GRANT
IX
1:280
UserTable
70
OBJECT
GRANT
IX
 
UserTable
70
KEY
GRANT
X
(c75ad92ba798)
UserTable
该事务持有的锁:
  1. 数据库层面的共享锁;
  2. 数据页上的意向排他锁;
  3. 数据表的意向排他锁;
  4. 数据行的排他锁;
结合上文中对于锁类型的讲解可以很容易理解数据库增加这些锁的用意 。数据库层面增加S锁可以保护当前正在进行的事务的安全,同时针对发生数据变化的数据页和数据表增加意向排他锁可以防止其他事务对于数据库和数据页进行更高层的修改(比如架构级别或者DDL之类的事务),IX锁对于IX和IS是可以并存的,因此可以最大限度上支持同一个区域内的其他修改和查询事务 。
SQL Server执行update时使用的锁首先在数据库中执行update语句而不提交(注意将上个章节中的事务提交或者回滚):
begin tran update UserTable set lastmodifytime=GETDATE()where id ='06757850-68D6-416C-B3D1-FD3B29BAD4BB'通过dm_tran_locks查询到该语句目前持有的锁:


推荐阅读