Chr*_*ris 64 c# sql-server ado.net deadlock transactionscope
我有一个在TransactionScope中运行的代码块,在这段代码中,我多次调用DB.选择,更新,创建和删除整个色域.当我执行删除操作时,我使用SqlCommand的扩展方法执行它,如果查询死锁,它将自动重新提交查询,因为此查询可能会遇到死锁.
我相信当遇到死锁并且函数尝试重新提交查询时会发生此问题.这是我收到的错误:
与当前连接关联的事务已完成但尚未处理.必须先处理事务,然后才能使用连接执行SQL语句.
这是执行查询的简单代码(下面的所有代码都在使用TransactionScope执行):
using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
sqlCommand.Connection.Open();
sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}
Run Code Online (Sandbox Code Playgroud)
以下是重新提交死锁查询的扩展方法:
public static class SqlCommandExtender
{
private const int DEADLOCK_ERROR = 1205;
private const int MAXIMUM_DEADLOCK_RETRIES = 5;
private const int SLEEP_INCREMENT = 100;
public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand)
{
int count = 0;
SqlException deadlockException = null;
do
{
if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT);
deadlockException = ExecuteNonQuery(sqlCommand);
count++;
}
while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES);
if (deadlockException != null) throw deadlockException;
}
private static SqlException ExecuteNonQuery(SqlCommand sqlCommand)
{
try
{
sqlCommand.ExecuteNonQuery();
}
catch (SqlException exception)
{
if (exception.Number == DEADLOCK_ERROR) return exception;
throw;
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
该行发生错误:
sqlCommand.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)
Dan*_*Dan 60
不要忘记从TransactionScope中压缩select语句.在SQL Server 2005及更高版本中,即使使用(nolock),仍然会在这些表上创建锁定选择触摸.看看这个,它会告诉你如何设置和使用TransactionScope.
using(TransactionScope ts = new TransactionScope
{
// db calls here are in the transaction
using(TransactionScope tsSuppressed = new TransactionScope (TransactionScopeOption.Suppress))
{
// all db calls here are now not in the transaction
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*cus 42
我发现当事务运行的时间比maxTimeoutfor 更长时,可能会出现此消息System.Transactions.无所谓TransactionOptions.Timeout增加,它不能超过maxTimeout.
默认值maxTimeout设置为10分钟,其值只能在.中修改machine.config
将以下内容(在配置级别中)添加machine.config到修改超时:
<configuration>
<system.transactions>
<machineSettings maxTimeout="00:30:00" />
</system.transactions>
</configuration>
Run Code Online (Sandbox Code Playgroud)
machine.config可以在以下位置找到: %windir%\Microsoft.NET\Framework\[version]\config\machine.config
您可以在此博客文章中阅读更多相关信息:http://thecodesaysitall.blogspot.se/2012/04/long-running-systemtransactions.html
Rol*_*olf 21
我可以重现这个问题.这是一个事务超时.
using (new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 0, 1)))
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (var sqlCommand = connection.CreateCommand())
{
for (int i = 0; i < 10000; i++)
{
sqlCommand.CommandText = "select * from actor";
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
抛出System.InvalidOperationException此消息:
与当前连接关联的事务已完成但尚未处理.必须先处理事务,然后才能使用连接执行SQL语句.
要解决此问题,请使查询运行得更快或增加超时.
Don*_*nie 11
如果内部发生异常TransactionScope,则会回滚.这意味着TransactionScope完成了.您现在必须调用dispose()它并开始新的事务.老实说,我不确定你是否可以重复使用旧的TransactionScope,我从未尝试过,但我不认为.
确认此错误也可能由事务超时引起.只是为了补充Marcus + Rolf所说的内容,如果你没有明确设置超时 TransactionScope,TimeSpan的超时将采用默认值.此默认值是以下值中的较小值:
如果你已经覆盖了本地app.config/ web.config设置,例如
<system.transactions>
<defaultSettings timeout="00:05:00" />
</system.transactions>
Run Code Online (Sandbox Code Playgroud)但是,这会被machine.config设置为"上限"<machineSettings maxTimeout="00:10:00" />