我在这段代码中使用TransactionScope:
private void ExecuteSP()
{
bool IsComplete = false;
SqlCommand sqlComm = null;
//6 hours!!!
TimeSpan ts1 = new TimeSpan(6, 0, 0);
try
{
using (TransactionScope t = new TransactionScope(TransactionScopeOption.RequiresNew, ts1))
{
using (SqlConnection sqlConn = new SqlConnection(GetConnectionString()))
{
//open sql connection
sqlConn.Open();
try
{
//create new sqlCommand
sqlComm = new SqlCommand();
for (int i = 1; i <= 2; i++)
{
IsComplete = true;
//This command takes 15 minutes
sqlComm.CommandText = "exec TestSp";
sqlComm.Connection = sqlConn;
sqlComm.CommandType = CommandType.Text;
sqlComm.CommandTimeout = 18000;
//Executing my command
int j = sqlComm.ExecuteNonQuery();
}
//End
t.Complete();
}
catch (Exception ex)
{
IsComplete = false;
string Message = ex.Message;
}
finally
{
if (sqlComm != null)
sqlComm.Dispose();
}
}
}
}
catch (Exception ex)
{
string messagee = ex.Message;
//do something
}
finally
{
MessageBox.Show("Finsh");
}
}在执行一次(sqlCommand.ExecuteNonQuery();)之后,执行时间超过10分钟就会发生。在这一点上我没有得到任何的解释,在下一次,我得到了一个例外:
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.这是因为System.Transactions.TransactionManager.MaximumTimeout设置为10分钟的TimeSpan。
我搜索并发现它可能与“System.Transaction->Machine.config的maxTimeout”有关,但在将配置更改为该文件后,我得到了一个异常:
<?xml version="1.0"?>
<configuration>
<system.transactions>
<machineSettings maxTimeout="10:00:00"/>
</system.transactions>
<appSettings>
<add key="FileName" value="MyFileName" />
<add key="MySpace" value="5 MB" />
<add key="ClientSettingsProvider.ServiceUri" value="" />
</appSettings>
</configuration>在更改配置文件后,当我试图在运行时获得System.Transactions.TransactionManager.MaximumTimeout时,会得到以下异常:
“配置系统初始化失败”
,有人知道如何解决这个问题吗?
(请注意我的情况:我需要执行大约20分钟的存储过程,因为我需要在SQL中将包含int的表转换为bigint (int =32位,bigint =64位)。我需要创建新表,并使用int64将数据从旧表插入到新表中。通过ID连接到其他4个表的表,每个表包含超过2000万行,还有绑定、索引等。我无法将此过程拆分为小型存储过程,因此需要将最大超时更改为一小时或更长时间,10分钟是不够的!)。
发布于 2012-07-03 15:38:37
如果您不害怕使用反射,则实际上可以以编程方式覆盖最大超时。这段代码不一定是未来的证明,但它在.NET 4.0中起作用。
public static class TransactionmanagerHelper
{
public static void OverrideMaximumTimeout(TimeSpan timeout)
{
//TransactionScope inherits a *maximum* timeout from Machine.config. There's no way to override it from
//code unless you use reflection. Hence this code!
//TransactionManager._cachedMaxTimeout
var type = typeof(TransactionManager);
var cachedMaxTimeout = type.GetField("_cachedMaxTimeout", BindingFlags.NonPublic | BindingFlags.Static);
cachedMaxTimeout.SetValue(null, true);
//TransactionManager._maximumTimeout
var maximumTimeout = type.GetField("_maximumTimeout", BindingFlags.NonPublic | BindingFlags.Static);
maximumTimeout.SetValue(null, timeout);
}
}你可以这样使用它:
TransactionmanagerHelper.OverrideMaximumTimeout(TimeSpan.FromMinutes(30));发布于 2011-06-19 14:07:30
您不能在您自己的配置文件中指定machineSettings,但是您需要在计算机的machine.config文件中实际更改/添加machineSettings\maxTimeout。
在您的计算机上,每32/64位和CLR版本组合就有一个此文件的实例。例如,32位版本的.NET 2.0文件位于%windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG目录中。64位.NET 2.0应用程序的文件位于%windir%\Microsoft.NET\Framework64\v2.0.50727\CONFIG目录中。同样,如果您使用的是.NET 4.0,则需要更改v4.0.30319\Config子目录中的文件。
请注意,通过更改此文件(正如名称所暗示的那样),可以更改框中每个事务的最大超时时间。所以小心你在这里设置的东西。在您的示例中,您应该将超时更改为10 (!)几个小时。
事务超时时间过长可能是一个问题,因为有时在到达超时之前无法检测到死锁。因此,有时无法及时发现这种情况。应该避免长时间运行的事务还有其他原因,但这实际上超出了这个问题/答案的范围。
无论如何,单独的应用程序仍然可以设置自己的最大超时,但是,使用自己的配置文件中的system.transactions部分,总是会被system.transactions文件中的超时设置为上限:
<system.transactions>
<defaultSettings timeout="22:00:00"/>
</system.transactions>注意,这里的元素名是defaultSettings,而不是machineSettings。
您还可以查看以下链接以获得更多信息:
发布于 2011-06-19 11:19:19
我从您的代码中注意到了一件与MS提供的示例不同的事情,那就是在完成SQL工作之前完成事务。
例如,
t.Complete(); 先于
if (sqlComm != null)
sqlComm.Dispose(); 您的t.complete();确实需要向下移动到sql段的末尾。我没有运行它来证明它的工作,但它是有意义的,因为您有一个事务部分,然后有进一步的工作,然后你告诉它已经完成。
我使用这个作为参考:http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx
https://stackoverflow.com/questions/6402031
复制相似问题