来源: 事务(进程 ID 51)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品_小白博客-CSDN博客
所有死锁的原因可归结为资源的竞争
表现一:
一个用户A 访问表A(锁住了表A),然后又访问表B 另一个用户B 访问表B(锁住了表B),然后企图访问表A 这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B,才能继续,好了他老人家就只好老老实实在这等了 同样用户B要等用户A释放表A才能继续这就死锁了
解决方法:
这种死锁是由于你的程序的'bug'产生的,除了调整你的程序的逻辑别无他法,仔细分析你程序的逻辑,
1:尽量避免同时锁定两个资源
2: 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源.
- 1
- 2
- 3
- 4
表现二:
用户A读一条纪录,然后修改该条纪录,这是用户B修改该条纪录这里用户A的事务里锁的性质由共享锁企图上升到独占锁(forupdate),而用户B里的独占锁由于A有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁
解决方法:
让用户A的事务(即先读后写类型的操作),在select 时就是用Update lock
语法如下:
select * from table1 (updlock) where ....
- 1
- 2
- 3
- 4
NOLOCK
NOLOCK在概念上类似于READ UNCOMMITTED隔离级别,并且只针对于SELECT查询语句,它不会获取表的共享锁,换句话说不会阻止排它锁来更新数据行。当我们对表进行NOLOCK有什么好处呢?它能够提高并发性能,因为此时SQL Server数据库引擎不必去维护共享锁,由于不会对正在读取的表获取共享锁,所以可能导致未提交的事务也会被读取,所以此时缺点显而易见将导致脏读
SELECT COUNT(*) FROM Example WITH(NOLOCK)
- 1
READPAST
当在表中用READPAST指定提示时此时SQL Server数据库引擎在返回结果集时将不会返回锁定的行或者数据页。它除了和NOLOCK一样不会导致查询阻塞外,因为不会返回锁定的行记录所以其优点好包括不存在脏读。但是其缺点则是因为不包含锁定的行记录但是很难保证结果集或者修改语句是否包含我们所必须需要返回的行。有可能在我们的业务逻辑中,需要返回我们必须需要的行。它的使用方式和NOLOCK一样
SELECT COUNT(*)FROM Example WITH(READPAST)
- 1
UPDLOCK
UPDLOCK只是针对于表中的某一行记录来锁定从而阻止其他操作对该行的数据更新,说到这里想必我们已经明了,UPDLOCK是行级别,而排它锁则是表级别,二者不可同日而语。也就说当我们对某一行添加UPDLOCK提示时并不会阻塞其他查询操作
BEGIN TRAN
select * from Example WITH (UPDLOCK) where SaleID = 1
此时我们再来开一个窗口进行查询,如下:
select * from Example
- 1
- 2
- 3
- 4
HOLDLOCK
使用HOLDLOCK提示时,此时查询将锁定表且被强制序列化,直到事务完成,才会被释放,其类似于SERIALIZABLE最高隔离级别
BEGIN TRAN
select * from Example WITH (UPDLOCK,HOLDLOCK) where SaleID = 1
- 1
- 2