数据库中死锁是啥产生的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库中死锁是啥产生的?相关的知识,希望对你有一定的参考价值。

参考技术A 数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL
Server
2005,
现在似乎有了一种新的解决办法。
将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁。
use
Northwind
begin
tran
  insert
into
Orders(CustomerId)
values(@#ALFKI@#)
  waitfor
delay
@#00:00:05@#
  select
*
from
Orders
where
CustomerId
=
@#ALFKI@#
commit
print
@#end
tran@#
SQL
Server对付死锁的办法是牺牲掉其中的一个,抛出异常,并且回滚事务。在SQL
Server
2000,语句一旦发生异常,T-SQL将不会继续运行,上面被牺牲的连接中,
print
@#end
tran@#语句将不会被运行,所以我们很难在SQL
Server
2000的T-SQL中对死锁进行进一步的处理。
现在不同了,SQL
Server
2005可以在T-SQL中对异常进行捕获,这样就给我们提供了一条处理死锁的途径:
下面利用的try
...
catch来解决死锁。
SET
XACT_ABORT
ON
declare
@r
int
set
@r
=
1
while
@r
<=
3
begin
  begin
tran
  begin
try   
    insert
into
Orders(CustomerId)
values(@#ALFKI@#)
    waitfor
delay
@#00:00:05@#
    select
*
from
Orders
where
CustomerId
=
@#ALFKI@#
    commit
    break
  end
try
  begin
catch
    rollback
    waitfor
delay
@#00:00:03@#
    set
@r
=
@r
+
1
    continue
  end
catch
end
解决方法当然就是重试,但捕获错误是前提。rollback后面的waitfor不可少,发生冲突后需要等待一段时间,@retry数目可以调整以应付不同的要求。
但是现在又面临一个新的问题:
错误被掩盖了,一但问题发生并且超过3次,异常却不会被抛出。SQL
Server
2005
有一个RaiseError语句,可以抛出异常,但却不能直接抛出原来的异常,所以需要重新定义发生的错误,现在,解决方案变成了这样:
declare
@r
int
set
@r
=
1
while
@r
<=
3
begin
  begin
tran
  begin
try   
    insert
into
Orders(CustomerId)
values(@#ALFKI@#)
    waitfor
delay
@#00:00:05@#
    select
*
from
Orders
where
CustomerId
=
@#ALFKI@#
    commit
    break
  end
try
  begin
catch
    rollback
    waitfor
delay
@#00:00:03@#
    set
@r
=
@r
+
1
    continue
  end
catch
end
if
ERROR_NUMBER()
<>
0
begin
  declare
@ErrorMessage
nvarchar(4000);
  declare
@ErrorSeverity
int;
  declare
@ErrorState
int;
  select
    @ErrorMessage
=
ERROR_MESSAGE(),
    @ErrorSeverity
=
ERROR_SEVERITY(),
    @ErrorState
=
ERROR_STATE();
  raiserror
(@ErrorMessage,
       
@ErrorSeverity,
       
@ErrorState
       
);
end

死锁产生的原因及避免死锁的方法

  • 死锁产生的原因: 两个进程都拿着对方需要的资源不放,而形成相互等待。
  • 如果不同程序会并发存取多个表/资源,尽量约定以相同的顺序访问表/资源,可以大大降低发生死锁的可能性; 注:不影响并发性能,是最经济的办法
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
  • 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。注:倒是不产生死锁了,但严重影响并发性能,是最后不得已的办法

以上是关于数据库中死锁是啥产生的?的主要内容,如果未能解决你的问题,请参考以下文章

数据库事务 - 怎样才能产生 互相等待 - 死锁,怎么解决

如何减少SQLServer死锁发生

数据库死锁怎么处理

mysql数据库死锁的产生原因及解决办法

减少SQL Server数据库死锁的技巧

当 Hangfire 并行处理多个作业时,为啥 MySQL InnoDB 会产生如此多的死锁?