书读百遍,不如 敲一遍代码...
先解释一下名词
共享锁(S):一般是Select 查询是自带共享锁;共享锁允许多个用户同时查询和修改(默认是这样,除非单独设置共享锁的生命周期,以下会说到);
排它锁(X):一般是Insert,Update,Delete时会自动加排它锁;
我们先看一个正常的例子:
一,
多个事务查询框模拟多个用户:
begin tran
-- S锁
select * from users where id= 1
--等待10秒
WaitFor DELAY '00:00:05'
commit;
begin tran
update users set Name= 'ttttt3' where id = 1
commit;
此时:第二个事务查询框不受第一个查询框的影响,可以直接出数据;证明Select的共享锁在查询后直接就默认释放掉了;
二,
begin tran
-- S锁
select * from users with(holdlock) where id= 1
--等待10秒
WaitFor DELAY '00:00:05'
commit;
begin tran
update users set Name= 'ttttt3' where id = 1
commit;
此时:第二个事务的更新操作受第一个事务的影响,需要等待5秒也就是第一个事务Commit的时候,才能执行;with(holdlock) 就是人为的提高了事务一Select共享锁的生命周期;
三,
begin tran
update users set Name= 'tt' where id = 1
WaitFor DELAY '00:00:05'
commit;
begin tran
-- S锁
select * from users where id= 1
commit;
此时:第二个事务的更新或者查询操作受第一个事务的影响,需要等待5秒也就是第一个事务Commit的时候,才能执行;第一个事务的update操作添加了排它锁,只有等commit提交事务的时候才会释放;
四,
begin tran
update users set Name= 'tt222' where id = 1
WaitFor DELAY '00:00:05'
commit;
--rollback
begin tran
-- S锁
select * from users with(nolock) where id= 1
commit;
此时:第二个事务者查询操作不受第一个事务的影响,可以直接出结果;但是第二个事物使用了with(nolock) 就是忽略锁的意思; 在第一个事务失败rollback的情况下可能会出现脏读的情况(第二个事物实际读取的是第一个事务的更新后的数据);
五,死锁
begin tran
update users set Name= 'tt'
WaitFor DELAY '00:00:05'
-- S锁
select * from uu with(holdlock)
commit;
begin tran
update uu set Name= 'ttttt3'
--WaitFor DELAY '00:00:50'
select * from users with(holdlock)
commit;
image.png
此时:
两个事务之间出现死锁; 事务一对users添加排它锁,并同时等待5秒钟; 事务二对uu 添加排它锁,并以(holdlock)方式 访问users表,但此时users排它锁并没有释放,所以无法添加共享锁,所以一直等待事务一释放排它锁;
此时事务一访问uu ,同样的uu排它锁并未释放,由此导致两个事务之间相互等待造成死锁;
死锁的造成方式还有很多种,总结就是对A中的A1添加了排它锁,在B中B1添加了排它锁,同时在A中访问B1,在B中访问A1,由此相互等待造成死锁;
最后附上锁类型:
HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁。
NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可能读到未提交读的数据或“脏数据”,这个选项仅仅应用于SELECT语句。
PAGLOCK:指定添加页锁(否则通常可能添加表锁)。
READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。
READPAST: 跳过已经加锁的数据行,这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行,而不是阻塞直到其他事务释放锁,READPAST仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作。
READUNCOMMITTED:等同于NOLOCK。
REPEATABLEREAD:设置事务为可重复读隔离性级别。
ROWLOCK:使用行级锁,而不使用粒度更粗的页级锁和表级锁。
SERIALIZABLE:用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。
1TABLOCK:指定使用表级锁,而不是使用行级或页面级的锁,SQL Server在该语句执行完后释放这个锁,而如果同时指定了HOLDLOCK,该锁一直保持到这个事务结束。
TABLOCKX:指定在表上使用排它锁,这个锁可以阻止其他事务读或更新这个表的数据,直到这个语句或整个事务结束。
UPDLOCK :指定在读表中数据时设置更新 锁(update lock)而不是设置共享锁,该锁一直保持到这个语句或整个事务结束,使用UPDLOCK的作用是允许用户先读取数据(而且不阻塞其他用户读数据),并且保证在后来再更新数据时,这一段时间内这些数据没有被其他用户修改。
网友评论