TransactionScope 提前完成
我有一个在 TransactionScope 内运行的代码块,并且在该代码块中我对数据库进行了多次调用。选择、更新、创建和删除整个范围。当我执行删除时,我使用 SqlCommand 的扩展方法来执行它,如果查询死锁,该方法将自动重新提交查询,因为该查询可能会遇到死锁。
我相信当遇到死锁并且函数尝试重新提交查询时就会出现问题。这是我收到的错误:
与当前连接关联的事务已完成但尚未释放。必须先释放事务,然后才能使用连接执行 SQL 语句。
这是执行查询的简单代码(下面的所有代码都在 TransactionScope 的使用中执行):
using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
sqlCommand.Connection.Open();
sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}
这是重新提交死锁查询的扩展方法:
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;
}
}
错误发生在该行:
sqlCommand.ExecuteNonQuery();
I have a block of code that runs within a TransactionScope and within this block of code I make several calls to the DB. Selects, Updates, Creates, and Deletes, the whole gamut. When I execute my delete I execute it using an extension method of the SqlCommand that will automatically resubmit the query if it deadlocks as this query could potentially hit a deadlock.
I believe the problem occurs when a deadlock is hit and the function tries to resubmit the query. This is the error I receive:
The transaction associated with the current connection has completed but has not been disposed. The transaction must be disposed before the connection can be used to execute SQL statements.
This is the simple code that executes the query (all of the code below executes within the using of the TransactionScope):
using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
sqlCommand.Connection.Open();
sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}
Here is the extension method that resubmits the deadlocked query:
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;
}
}
The error occurs on the line:
sqlCommand.ExecuteNonQuery();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不要忘记抑制 TransactionScope 中的 select 语句。在 SQL Server 2005 及更高版本中,即使您使用 with(nolock),仍然会在 select 涉及的那些表上创建锁。看看这个,它向您展示了如何设置和使用 TransactionScope。
Don't forget to supress your select statements from your TransactionScope. In SQL Server 2005 and above, even when you use with(nolock), locks are still created on those tables the select touches. Check this out, it shows you how to setup and use TransactionScope.
我发现当事务运行时间长于
System.Transactions
的maxTimeout
时,可能会出现此消息。TransactionOptions.Timeout
增加没关系,它不能超过maxTimeout
。maxTimeout
的默认值设置为 10 分钟,其值只能在machine.config
中修改添加以下内容(在配置中) level) 到
machine.config
以修改超时:machine.config 可以在以下位置找到:
%windir%\Microsoft.NET\Framework\[version]\config\machine.config
您可以在这篇博文中了解更多相关信息:http: //thecodesaysitall.blogspot.se/2012/04/long-running-systemtransactions.html
I've found that this message can occur when a transaction runs for a longer period than the
maxTimeout
forSystem.Transactions
. It doesn't matter thatTransactionOptions.Timeout
is increased, it can't exceedmaxTimeout
.The default value of
maxTimeout
is set to 10 minutes and its value can only be modified in themachine.config
Add the following (in the configuration level) to the
machine.config
to modify the timeout:The machine.config can be found at:
%windir%\Microsoft.NET\Framework\[version]\config\machine.config
You can read more about it in this blog post: http://thecodesaysitall.blogspot.se/2012/04/long-running-systemtransactions.html
我可以重现该问题。这是事务超时。
抛出
System.InvalidOperationException
并显示以下消息:要解决该问题,请使查询运行得更快或增加超时。
I can reproduce the problem. It is a transaction timeout.
Throws
System.InvalidOperationException
with this message:To solve the problem make your query run faster or increase the timeout.
如果在
TransactionScope
内发生异常,则会回滚。这意味着TransactionScope
已完成。您现在必须对其调用dispose()
并启动新事务。老实说,我不确定您是否可以重用旧的TransactionScope
,我从未尝试过,但我认为不能。If an exception happens inside a
TransactionScope
it is rolled back. This means thatTransactionScope
is done. You must now calldispose()
on it and start a new transaction. I'm honestly not sure if you can reuse the oldTransactionScope
or not, I've never tried, but I'd assume not.我的问题是一个愚蠢的问题,如果你在超时时进行调试突破,你就会得到这个。 Face Palm
伙计,编程有时会让你感觉很厚重……
My issue was a stupid one, if you sit on a debug break through the timeout you will get this. Face Palm
Man, programming makes you feel thick some days...
确认此错误也可能是由事务超时引起的。只是为了补充 Marcus + Rolf 所说的内容,如果您没有在
TransactionScope
上显式设置超时,则超时 TimeSpan 将采用默认值。此默认值是以下值中的较小:如果您已覆盖本地
app.config
/web.config
设置,例如< /p>But this is then 'capped' at
machine.config
设置Confirmed this error can also be caused by a transaction timeout. Just to add to what Marcus + Rolf have stated, if you haven't explicitly set a timeout on the
TransactionScope
, the timeout TimeSpan will assume a default value. This default value is the smaller of:If you've overridden the local
app.config
/web.config
setting, e.g.But this is then 'capped' at the
machine.config
setting<machineSettings maxTimeout="00:10:00" />
此异常也可能是由禁用
Microsoft 分布式事务协调器
引起的。如果我们想启用它,我们运行“dcomcnfg”并选择
“组件服务”-> “我的电脑”-> 《分布式事务协调器》-> “本地服务 DTC”
并选择“属性”。应选中“允许远程客户端”、“允许入站”、“允许出站”和“无需身份验证”强>”。
This exception can also be caused by disable
Microsoft Distributed Transaction Coordinator
.If we want enable it, we run "dcomcnfg" and select
"Component Services" -> "My Computer" -> "Distributed Transaction Coordinator" -> "Local Service DTC"
and choose "Properties".It should be checked "Allow Remote Client", "Allow Inbound", "Allow Outbound" and "No Authentication Required".