1、如果多个update是一个事务里面的话,update会到事务结束才释放锁,而不是第一个update之后就释放。 2、按你说的应该是B先update,这样就获取了资源上的一个锁,而A接着UPDATE,就会申请相同资源上的锁,因为B锁住了,所以A等待,然后B的第一个update结束了开始第二个update,这时候它就等待A释放U锁(update是先申请U锁再转换成X锁),这样一来就互相等待,最后死锁。 例子: /* 创建50万数据表,无索引 */ SELECT TOP 500000 ROW_NUMBER()OVER(ORDER BY GETDATE())id,'a' AS NAME INTO TestTB FROM sys.syscolumns a CROSS JOIN sys.syscolumns b在第一个窗口输入(模拟B) BEGIN TRAN UPDATE testtb SET NAME='b' WHERE id=10WAITFOR DELAY '00:00:10'UPDATE testtb SET NAME='c' WHERE id=100WAITFOR DELAY '00:00:10'UPDATE testtb SET NAME='d' WHERE id=10000 ROLLBACK 在第二个窗口输入(模拟A) BEGIN TRAN UPDATE testtb SET NAME='b' WHERE id=908 --ROLLBACK先执行B,再马上执行A,就看到这样的结果:
2、insert 和update考虑是否能分到2个事务中完成
如果我将update的表加聚焦索引应该会解决这个问题.
但是我还是不明白我这个锁的根本原因在哪里.
因为即使是整表锁,我也不知道为什么我发生死锁.
insert没有where条件的.
2、insert不排除会锁表,要看插入时是否顺序插入。
3、你的死锁是因为:
A B
update --速度太慢锁表 insert --一般没问题
insert --一般没问题 update --因为A可能还没完成,所以要等这个问题主要是看谁先获取锁并且要申请什么锁。解决建议:
1、对XXX表加聚集索引,并且看是否需要加非聚集索引协助UPDATE,这是重点,update如果快,或者锁资源的粒度很小,那么对其他影响就不大。
2、如果insert /update没有直接的关联关系,可以放到两个事务中,并且完成事务后马上commit、回滚
3、实在不行的情况下,使用快照隔离模式,不过这个有点难度
B就等一会就好了,等A完成了,就可以了.必须是永远等不到才会称为死锁吧?
我这里B做update的时候会对XXX表执行多次update,这个会是问题的关键吗?
会,因为没有合适的索引,所以每次update都是锁表,
假设A也有多次update,b也有
再假设a是首先发生的,第一次Update时锁了一次,然后B开始update,而A过了短暂时间又要update,B又要update,都发生在相同的表资源上,就造成互相等待
B有多次,
如果A先锁表,则B一直等到A完成再操作,貌似不会死锁
如果B先锁表,A等待B所有循环update做完以后再操作,貌似也不会死锁,老大,这个死锁到底是怎么回事呢?
2、按你说的应该是B先update,这样就获取了资源上的一个锁,而A接着UPDATE,就会申请相同资源上的锁,因为B锁住了,所以A等待,然后B的第一个update结束了开始第二个update,这时候它就等待A释放U锁(update是先申请U锁再转换成X锁),这样一来就互相等待,最后死锁。
例子:
/*
创建50万数据表,无索引
*/
SELECT TOP 500000 ROW_NUMBER()OVER(ORDER BY GETDATE())id,'a' AS NAME INTO TestTB
FROM sys.syscolumns a CROSS JOIN sys.syscolumns b在第一个窗口输入(模拟B)
BEGIN TRAN
UPDATE testtb
SET NAME='b'
WHERE id=10WAITFOR DELAY '00:00:10'UPDATE testtb
SET NAME='c'
WHERE id=100WAITFOR DELAY '00:00:10'UPDATE testtb
SET NAME='d'
WHERE id=10000
ROLLBACK
在第二个窗口输入(模拟A)
BEGIN TRAN
UPDATE testtb
SET NAME='b'
WHERE id=908
--ROLLBACK先执行B,再马上执行A,就看到这样的结果:
解決的方法,可以在update的語句指定rowlock.
(使用rowlock的時候非常小心,氾濫使用會佔用大量的內存和CPU資源)
看来我的处理方式也只有是加聚焦索引了,
这样update的时候就只锁行了,这样就OK了.至少我以我这边的业务逻辑就OK的,因为我这边2个事务更新的行是不交叉的.所以锁行是不会再死锁的了.
但是如果搜索条件不是索引的话就会全表扫描.这样就锁表了.
我现在是这样理解的,不知道对吗?