关键词:
一直没有认真了解UPDATE操作的锁。近期在MSDN论坛上看到一个问题,询问堆表更新的死锁问题,问题非常easy,有相似这种表及数据:
CREATE TABLE dbo.tb(
c1 int,
c2 char(10),
c3 varchar(10)
);
GO
DECLARE @id int;
SET @id = 0;
WHILE @id <5
BEGIN;
SET @id = @id + 1;
INSERT dbo.tb VALUES( @id, ‘b‘ + RIGHT(10000 + @id, 4), ‘c‘ + RIGHT(100000 + @id, 4) );
END;
在查询一中运行更新操作:
BEGIN TRAN
UPDATE dbo.tb SET c2 = ‘xx‘ WHERE c1 = 2;
WAITFOR DELAY ‘00:00:30‘;
UPDATE dbo.tb SET c2 = ‘xx‘ WHERE c1 = 5;
ROLLBACK;
在查询一运行開始后,立即在查询二中运行以下的操作
BEGIN TRAN
UPDATE dbo.tb SET c2 = ‘xx‘ WHERE c1 = 1;
ROLLBACK;
为什么会出现死锁,假设条件改为 c1 = 4 则不会死锁。
開始的时候想得比較简单,死锁的表现是形成循环等待(对于两个查询而言,能够简单地觉得就是在相互等待对方锁定资源的释放)。
对于这个样例而言。第一个查询更新两次,会先更新并锁定一条记录,然后等待第二个更新。但第二个查询仅仅会更新一条记录。它要么与第一个查询冲突,无法获得锁。须要等待查询一完毕,这个时候它并没有锁定什么;要么能够获得锁,完毕更新。
似乎不应该会出现死锁,死锁会不会是其它原因导致。
在自己的电脑上简单測试了一下。似乎也确实没有死锁。
但后面通过Profile跟踪更新操作的下锁情况才发现。自己的分析大错特错了。
主要原因在于没有正确理解更新操作是怎样用锁的。
在联机帮助上“锁模式”中有关于更新的U(更新锁)和X(排它锁)的说明
http://msdn.microsoft.com/zh-cn/library/ms175519(v=sql.105).aspx
只是说得确实挺模糊的。里面还提到了S锁。我一直以为是查询数据过程中用的S锁(也 SELECT 一样)。找到满足条件的记录后用U锁,再转换为X锁做更新。
Profile(事件探查器)跟踪的结果让我知道了这是一个错误的理解,在Profile中新建一个跟踪,选择Locks中的Lock:Acquired (加锁),Lock:Acquired(释放锁)解两个事件,在筛选中设置仅仅跟踪測试用的查询窗体相应的spid(能够运行 PRINT @@SPID 获得),然后运行一个更新语句。比方 UPDATE dbo.tb SET c2 = ‘xx‘ WHERE c1 = 3
在Profile中能够看到。对于每条记录都有加 U 锁的操作,对于不满足条件的记录,会立即释放U锁;对于满足条件的记录,终于转换为X锁。例如以下图所看到的。
注意一下,在这个跟踪结果里面。并没有出现S锁。
另外学做了一些測试:
通过加大记录量做更新測试,会发现数据扫描涉及的记录都有U锁,并不限于更新记录所在的页。这从还有一个角度说明了大表中Scan 可怕。
当使用索引Scan的时候,也会通过跟踪发现所Scan的索引资源有U锁,假设更新不涉及索引变化。那以仅仅会相应的记录有U转X锁。索引的U锁会释放;假设影响索引,那么索引的U锁会转X锁。
删除操作与更新操作相似
使用 UPDATE aSET c2 = ‘xx‘ FROM dbo.tb AS a WITH(NOLOCK) WHERE c1 = 3 的加锁情况是一样的。 并不会由于NOLOCK的提示而不加 U 或者 X 锁
最后回头研究一下演示样例中的死锁问题:
对于查询一,第一个更新依次扫描表中全部记录,对于每条记录,加 U 锁,推断是否符合更新条件。假设符合,转换为 X 锁;假设不符合条件。释放 U 锁。第一个更新完毕的时候,查询一锁定了一条记录(由于事务未完毕,所以锁一直保持),然后等待第二个更新
对于查询二,依次扫描表中的每条记录(与前面的更新一样),假设它更新的记录在查询一更新的记录前被扫描到,那么这条记录也会变成 X 锁;当继续并进行到查询一的X锁记录的零点,U 与 X 冲突,无法继续,这时候查询二等待查询一释放锁
查询一的第二个更新開始运行。依次扫描每条记录。同一个事务内不会有冲突。所以它不会与自己之前锁定的记录有冲突,但进行到查询二锁定的记录的时候,它也无法获得 U 锁。它须要等待查询二释放资源。
这个时候就形成了相互等待,符合死锁条件
假设查询二须要更新的记录在查询一的第一个更新记录之后。则不会有死锁。由于查询二在扫描到查询一第一个更新的记录时就会由于锁冲突等待了,这个时候它没有对不论什么记录设置与查询一的操作有冲突的锁。我自己測试的时候没有死锁,就是这种情况。
注意这里面提到的顺序。是数据读取的顺序,不一定与存储顺序一样,磁盘上记录的顺序也不一定与INSERT的记录顺序一样,这也是我用相同条件没有測试出死锁的原因(我的环境中,恰好读出的顺序与INSERT的顺序不一样)
更新时,记录读取的顺序,能够通过Profile跟踪的Lock:Acquired (加锁)事件来看。涉及大量数据时,假设server支持。还会有并发读取。这也是分析死锁时要考虑的因素
共享锁(s锁)和排它锁(x锁)
...用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。共享锁(S锁)又称为读锁,若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这... 查看详情
共享锁和排它锁的理解
...T对数据对象A加了S锁,则T就可以对A进行读取,但不能进行更新(S锁因此又称为读锁),在T释放A上的S锁以前,其他事务可以再对A加S锁,但不能加X锁,从而可以读取A 查看详情
基于mysql排它锁实现分布式可重入锁解决方案(代码片段)
一、MySQL排它锁和共享锁在进行实验前,先来了解下MySQL的排它锁和共享锁,在MySQL中的锁分为表锁和行锁,在行锁中锁又分成了排它锁和共享锁两种类型。1.排它锁排他锁又称为写锁,简称X锁,是一种悲观锁... 查看详情
day1812.丢失更新介绍与悲观锁
共享锁在一条记录上是可以加多个的,共享嘛。排它锁的意思是指这条记录上如果有任何其他的锁我排它锁是加不上的,有了排它锁其他锁也是加不上的,唯一的。比如说现在我的记录上没锁,加了排它锁其他人使用不了,我这排它锁... 查看详情
共享锁(s锁)和排它锁(x锁)
共享锁【S锁】又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。排他锁【... 查看详情
共享锁(s锁)和排它锁(x锁)
共享锁【S锁】又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。排他锁【... 查看详情
共享锁和排它锁的理解
...T对数据对象A加了S锁,则T就可以对A进行读取,但不能进行更新(S锁因此又称为读锁),在T释放A上的S锁以前,其他事务可以再对A加S锁,但不能加X锁,从而可以读取A,但不能更新A.若事务T1对数据A加了排他锁,但是事务T2只想读数据A而... 查看详情
事务和锁
...A上的锁之前不能再读取和修改A。 1、什么是共享锁和排它锁 共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。 排它锁,也称作独占锁,一个锁在某一时刻只能被一个... 查看详情
锁定机制和数据并发管理(笔记)
共享锁和排它锁排它锁:当某一个会话正在更新某一行,为了防止其他会话修改这一行,这行会被锁定这种锁称为排他锁。被排他锁锁定的行仍然可以被其他会话读取。 共享锁:在一个表上放置共享锁的目的是为了防止其他... 查看详情
pg基础篇--逻辑结构管理(锁机制)
行锁分类行锁只有共享锁和排它锁,pg不称读锁的原因是由于有多版本的实现,实际读取数据时,并不会在行上执行任何锁死锁死锁发生的四个必要条件(1)互斥条件:指事务对所分配到的资源加了排它锁,即在一段时间内只能... 查看详情
对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解(代码片段)
...的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁) 查看详情
核心面试题:mvcc间隙锁undolog链表级锁行级锁页级锁共享锁排它锁记录锁等等(代码片段)
文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+... 查看详情
锁的总结
...可重入锁与非可重入锁 公平锁与非公平锁 共享锁与排它锁 自旋锁与阻塞锁 可中断锁 锁优化 一:Lock接口1.锁 是一种工具,用于控制对共享资源的访问 Lock和synchronized,是常见的锁,都可以达到线... 查看详情
mysql锁详解
...改查的加锁情况:delete:加X锁insert:一般情况不加锁update:不更新ID值,则加X锁。更新ID值,相当 查看详情
使用sqlserver数据库,如何对数据项加s锁或x锁呢??
...数据库的并发操作时会带来以下数据不一致的问题:丢失更新A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统脏读A用户修改了数据,随后B用户又读出该数据,但A用户因为某些原因... 查看详情
sqlserver数据库select操作会造成锁表吗
...库系统的角度来看锁分为独占锁(即排它锁),共享锁和更新锁MS-SQLServer使用以下资源锁模式。锁模式描述共享(S)用于不更改或不更新数据的操作(只读操作),如SELECT语句。更新(U)用于可更新的资源中。防止当多个会话在读取... 查看详情
数据库的事物隔离级别以及锁的一些个人理解
数据库的基本分为共享锁和排它锁排它锁顾名思义,不能和其他任何所共存。以SqlServer中某一行数据为例,特殊的,WithNoLock这个是不给数据加上任何锁,所以根本和锁没关系再说update,update的过程是给这条数据加上排它锁,所... 查看详情
悲观锁/乐观锁/排它锁/共享锁/表级锁/行级锁/死锁
...志伟🍊社区:幕后大佬文章目录悲观锁/乐观锁/排它锁/共享锁/表级锁/行级锁/死锁悲观锁乐观锁行锁和表锁表级锁行锁死锁本文内容:悲观锁/乐观锁/排它锁/共享锁/表级锁/行级锁/死锁悲观锁每次去拿数据的时候都... 查看详情