不介绍背景,直接上例子
首先我们创建这样的一张表,没有主键,添加下面的数据
然后我们分别创建下面的连个连接查询
查询1:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--SERIALIZABLE
--READ
UNCOMMITTED
begin tran
print
convert(nvarchar(30),convert(datetime,getdate(),121),121)
update
table1
set A=‘aa‘
where B=‘b2‘
-- print
convert(nvarchar(30),convert(datetime,getdate(),121),121)
waitfor delay
‘00:00:10‘
update table1
set A=‘aa‘
where B=‘b4‘
--EXEC
sp_lock2 @@spid
EXEC sp_lock @@spid
print
convert(nvarchar(30),convert(datetime,getdate(),121),121)
commit tran
查询2:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--DBCC
USEROPTIONS
--begin try
begin tran
print
convert(nvarchar(30),convert(datetime,getdate(),121),121)
update table1
set A=‘aa‘
where B=‘b8‘
--EXEC sp_lock2 @@spid
waitfor delay ‘00:00:5‘
EXEC sp_lock @@spid
print
convert(nvarchar(30),convert(datetime,getdate(),121),121)
commit tran
首先执行查询一,然后马上切换到查询二
再马上暂停查询二,执行
EXEC sp_lock @@spid
发现结果是:
最后一条记录对应的就是table1,这时我们会看到在table1上已经加上了表的意向锁。
如果不做停止操作,执行的结果不会有异常。
然后我们再调整一下查询2:
update table1
set A=‘aa‘
where
B=‘b1‘
重复上面的步骤会发现执行的锁信息如下:
这时我们会发现执行的结果出现异常
消息 1205,级别 13,状态 45,第 6
行
事务(进程 ID 53)与另一个进程被死锁在 锁
资源上,并且已被选作死锁牺牲品。请重新运行该事务。
其中有一个规律,我们查询一中有B=‘b2‘,如果查询二中的条件值在b2之前就会出现死锁,而在b2之后就会正常执行事务。
我们来看一下查询一,在执行过程中的锁信息:
当执行查询一的过程中,再执行查询二,对于第一种情况,将整个表加上了意向锁,等待查询一结束释放资源后再
执行查询二,而对于第二种情况则出现了资源的争夺,导致死锁。
在这个过程中我们看到了IX,IX是意向锁,什么是意向锁呢?
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。
当我们给行记录加上X锁的时候,就会在page和TAB上加意向锁。
例如,对任一元组加锁时,必须先对它所在的关系加意向锁。
于是,事务T要对关系R1加X锁时,系统只要检查根结点数据库和关系R1是否已加了不相容的锁,而不再需要搜索和检查R1中的每一个元组是否加了X锁。
待续。。。
更新一张没有主键的数据表,引发的死锁,布布扣,bubuko.com