Joa*_*rel 88 .net deadlock sqlexception try-catch sql-server-2008
从.NET 3.5/C#应用程序,我想抓住,SqlException但只有它是由 SQL Server 2008实例上的死锁引起的.
典型的错误消息是 Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
但是,对于此异常,它似乎不是一个记录错误代码.
针对其消息中存在死锁关键字而过滤异常似乎是实现此行为的一种非常难看的方式.有人知道这样做的正确方法吗?
Ada*_*Dev 146
针对死锁的Microsft SQL Server特定错误代码是1205,因此您需要处理SqlException并检查它.因此,例如,如果对于所有其他类型的SqlException,您希望气泡异常:
catch (SqlException ex)
{
if (ex.Number == 1205)
{
// Deadlock
}
else
throw;
}
Run Code Online (Sandbox Code Playgroud)
或者,使用C#6中提供的异常过滤
catch (SqlException ex) when (ex.Number == 1205)
{
// Deadlock
}
Run Code Online (Sandbox Code Playgroud)
查找给定消息的实际SQL错误代码的一个方便的事情是查看SQL Server中的sys.messages.
例如
SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033
Run Code Online (Sandbox Code Playgroud)
处理死锁(来自SQL Server 2005及更高版本)的另一种方法是使用TRY ... CATCH支持在存储过程中执行此操作:
BEGIN TRY
-- some sql statements
END TRY
BEGIN CATCH
IF (ERROR_NUMBER() = 1205)
-- is a deadlock
ELSE
-- is not a deadlock
END CATCH
Run Code Online (Sandbox Code Playgroud)
有一个完整的例子这里在如何SQL内纯粹实施僵局重试逻辑MSDN.
Ste*_*ven 43
因为我想你可能想要检测死锁,为了能够重试失败的操作,我想警告你一点点陷阱.我希望你能原谅我在这里有点偏离主题.
数据库检测到的死锁将有效地回滚您运行的事务(如果有),而连接在.NET中保持打开状态.重试该操作(在同一连接中)意味着它将在无事务上下文中执行,这可能导致数据损坏.
重要的是要意识到这一点.最好考虑在SQL导致失败的情况下注定完整的连接.重试操作只能在定义事务的级别上完成(通过重新创建该事务及其连接).
因此,当您重试失败的操作时,请确保打开一个全新的连接并开始新的事务.
这是检测死锁的 C# 6 方法。
try
{
//todo: Execute SQL.
//IMPORTANT, if you used Connection.BeginTransaction(), this try..catch must surround that code. You must rollback the original transaction, then recreate it and re-run all the code.
}
catch (SqlException ex) when (ex.Number == 1205)
{
//todo: Retry SQL
}
Run Code Online (Sandbox Code Playgroud)
确保此 try..catch 包围您的整个事务。根据@Steven(详细信息请参阅他的答案),当sql命令由于死锁而失败时,它会导致事务回滚,如果您不重新创建事务,您的重试将在上下文之外执行事务,可能会导致数据不一致。
| 归档时间: |
|
| 查看次数: |
49713 次 |
| 最近记录: |