默认事务超时

Posted

技术标签:

【中文标题】默认事务超时【英文标题】:Default Transaction Timeout 【发布时间】:2010-11-23 19:23:02 【问题描述】:

我曾经使用 TransactionOptions.Timeout 设置事务超时,但为了便于维护,我决定使用配置方法:

 <system.transactions>
    <defaultSettings timeout="00:01:00" />
  </system.transactions>

当然,在放入之后,我想测试它是否正常工作,因此将超时时间减少到 5 秒,然后运行一个持续时间比这更长的测试 - 但事务似乎没有中止!如果我调整测试以将 TransactionOptions.Timeout 设置为 5 秒,则测试按预期工作

经过调查,我认为问题似乎与 TransactionOptions.Timeout 有关,即使我不再使用它。

我仍然需要使用TransactionOptions,所以我可以设置IsolationLevel,但是我不再设置Timeout值,如果我在创建它后查看这个对象,超时值是00:00:00,相当于无穷大。这是否意味着我在配置文件中设置的值被忽略了?

总结一下:

是否无法混合配置 设置和使用 交易选项 如果没有,是否有 任何方式来提取配置设置 在运行时,并使用它来设置 超时属性 [Edit] OR 设置默认隔离级别而不使用 TransactionOptions

【问题讨论】:

你在哪个配置文件中设置了这个?在哪个配置部分? 根目录下的 app.confing 中。也在 web.config 中,但上面的测试是针对 app.config 的。 【参考方案1】:

您可以使用 TransactionManager.DefaultTimeout 从配置中获取(已验证的)默认超时。

TransactionOptions 是一个封装了超时和隔离级别的结构体。当使用默认构造函数初始化struct 时,它总是将结构成员初始化为其默认值:

TransactionOptions transactionOptions = new TransactionOptions();
transactionOptions.Timeout == default(TimeSpan); // TimeSpan.Zero
transactionOptions.IsolationLevel == default(IsolationLevel); // IsolationLevel.Serializable

如果要指定IsolationLevel 并使用默认超时:

new TransactionOptions()

    IsolationLevel = IsolationLevel.Serializable, // Use whatever level you require
    Timeout = TransactionManager.DefaultTimeout
;

【讨论】:

这是我一直希望的答案!不幸的是,我给你答案为时已晚,但 TransactionManager.DefaultTimeout 绝对是我想要的。感谢发帖! 我还注意到微软也在他们的documentation on System.Transactions 中使用了这种技术。感谢您提供有用的信息! ILSpy 中的 FWIW Groveling 在 .NET 4.0 中显示默认值为 1 分钟,请记住这是一个实现细节,因此可能会发生变化,请使用上述内容再次检查此值!:// System. Transactions.Configuration.DefaultSettingsSection [ConfigurationProperty("timeout", DefaultValue = "00:01:00"), TimeSpanValidator(MinValueString = "00:00:00", MaxValueString = "10675199.02:48:05.4775807")] @aolszowka TransactionManager.DefaultTimeout的值配置文件中指定的值。默认值确实是1分钟,可以通过编辑DefaultSettingsSection.Timeout来修改,所以不需要复查! machineSettings 或 TransactionManager.DefaultTimeout ?【参考方案2】:

您可以混合使用 system.transaction 配置设置和 TransactionOption 类的使用,但您需要注意一些事项。

如果您使用 TransactionOption 和 指定一个Timeout 值,该值 将用于 system.transactions/defaultTimeout 价值。

以上是我认为您的问题的症结所在。您正在使用 TransactionOption 指定 isolation 级别,并且作为副作用,您将获得 infinite 超时值,因为无限是 TransactionOption 的默认超时值如果未指定。不过,我不太清楚为什么会这样……默认为默认事务超时是有意义的。

您可以实现自己的 TransactionOptions 助手类,其中包括从 app.config 读取的默认值(如果找到)或默认为可以使用的 TransactionOption 类的合理值。

无论如何,您仍然可以通过使用 system.transaction/machineSettings/maxTimeout 值来限制这一点。这是一个管理设置,只能通过 machine.config 进行配置。如果你从 app/web.config 尝试,你会得到一个 ConfigurationException。

<system.transactions>
    <machineSettings maxTimeout="00:00:30" />
</system.transactions>

ma​​xTimeout 设置后,无论您指定什么超时值,最大值都将限制为 maxTimeout 值。默认的 maxTimeout 是 00:10:00,即 10 分钟,因此您实际上不会在事务中遇到无限超时。

您还可以在事务中使用的数据库连接上显式设置事务 IsolationLevel。像这样?

   var connectionString = "Server=.;Database=master;Trusted_Connection=True;";

            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            
                using (var conn = new SqlConnection(connectionString))
                
                    conn.Open();
                    var sqlTransaction = conn.BeginTransaction(System.Data.IsolationLevel.Serializable);

                    // do database work
                    //
                    sqlTransaction.Commit();


                

                // do other work..
                //

                scope.Complete();

            

在您的测试中,您可能需要确保重新生成 app.config 以便重新生成。在我的测试中,我似乎需要终止 *.vshost.exe 进程才能让它接受 system.transaction 配置设置更改——尽管我觉得这可能是侥幸。仅供参考..

【讨论】:

【参考方案3】:

对于Reflector来说,使用TransactionScope的构造函数设置事务超时的基本规则如下:

DefaultTimeOut 由下面满足的第一条规则确定:

如果构造函数有TimeSpan 参数,DefaultTimeout 就是那个参数 如果构造函数有TransactionOption参数,则DefaultTimeout为transactionOption.TimeOut 如果构造函数有TransactionScopeOption参数,则DefaultTimeout为scopeOption.TimeOut 如果构造函数没有超时参数,则 DefaultTimeout 是在应用程序或 Web 配置文件中指定的值。 否则,DefaultTimeOut 为 1 分钟。

MaxTimeOut 为 10 分钟,除非在 machine.config 中指定了另一个值。

事务的有效超时小于大于零的 MaxTimeOut 和 DefaultTimeOut。如果 MaxTimeOut 和 DefaultTimeOut 都为零,则有效超时是long.MaxValue 表示的滴答数(无穷大)。

如果TransactionScope 实例没有创建新事务,要么是因为事务被传递到其构造函数中,要么是因为事务范围选项不需要它(例如,当存在环境事务并且需要 TransactionScopeOption 时) ,但是在构造函数中仍然传递了timeOut参数,启动了一个计时器。当超时时间过去时,底层事务的TimeOut() 方法被调用。在这种情况下不使用 DefaultTimeOut 和 MaxTimeOut 属性。

如果是transactionScopeOption == TransactionScopeOption.Supress,超时被忽略,没有任何作用。

如果 machine.config 中的相关部分被覆盖(注意 allowDefintion 和 allowExeDefinition 属性的值),也可以在 app/web 配置文件中定义 MaxTimeOut:

<sectionGroup name="system.transactions" type="System.Transactions.Configuration.TransactionsSectionGroup, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null">
    <section name="defaultSettings" type="System.Transactions.Configuration.DefaultSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/>
    <section name="machineSettings" type="System.Transactions.Configuration.MachineSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null" allowDefinition="MachineToApplication" allowExeDefinition="MachineToApplication"/>
</sectionGroup>

为了快速参考,这里是 TransactionScope 构造函数:

public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout, EnterpriseServicesInteropOption interopOption);
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions, EnterpriseServicesInteropOption interopOption);
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions);
public TransactionScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout);
public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout);
public TransactionScope(TransactionScopeOption scopeOption);

【讨论】:

【参考方案4】:

使用 TransactionOptions 时忽略配置文件设置。在大多数情况下,创建 TransactionScope 将创建 CommittableTransaction 的实例。 CommittableTransaction 的无参数构造函数将使用配置文件设置作为其默认超时。采用 TransactionOptions 或 TimeSpan 的 TransactionScope 构造函数将调用 CommittableTransaction 类的重载之一,而不是无参数版本。因此,如果您想使用该值,您必须自己从配置文件中获取它。

当我遇到这个问题时,我将以下代码放在一个小的 TransactionOptionsFactory 类中。


Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSectionGroup sectionGroup = configuration.GetSectionGroup("system.transactions");
DefaultSettingsSection defaultSettings = (DefaultSettingsSection) sectionGroup.Sections["defaultSettings"];
TransactionOptions options = new TransactionOptions();
options.Timeout = defaultSettings.Timeout;
options.IsolationLevel = IsolationLevel.ReadCommitted;

【讨论】:

抱歉,迈克,我会奖励你赏金的,但我显然比赏金截止日期晚了一个小时。该解决方案将非常巧妙地解决我的问题。遗憾的是,API 对此并不清楚。 不用担心,马特。我很高兴它有所帮助。【参考方案5】:
void Main()

    var maximumTimeout = TransactionManager.MaximumTimeout;//This step is necessary to init _maximumTimeout value, 

    FieldInfo fieldInfo = typeof(TransactionManager).GetFields(BindingFlags.NonPublic | BindingFlags.Static).Single(item => item.Name == "_maximumTimeout");
    var customMaximumTimeout = TimeSpan.FromHours(1);
    fieldInfo.SetValue(null, customMaximumTimeout);
    maximumTimeout = TransactionManager.MaximumTimeout;

    Console.WriteLine(maximumTimeout);//01:00:00
    // use TransactionScope

【讨论】:

正如弗朗茨简明扼要地指出的那样——你可以通过反射来做到这一点。我在这篇 MSDN 文章的 cmets 中找到了另一种方法:blogs.msdn.com/b/ajit/archive/2008/06/18/… - 不幸的是,我公司的 DevOps 情况并不是我需要的,所以我没有简单的方法来更新 machine.config处理节点并将设置应用于未来的节点。使用反射对我来说是一个很好的解决方法。【参考方案6】:

把我现在的想法记下来:

无法混合配置设置和使用TransactionOptions 在运行时提取配置设置的唯一方法是将 app.config 读取为 XML 文件 默认隔离级别只能通过事务选项完成,或者在 WCF 中使用属性在服务级别完成

【讨论】:

至第二个要点:有一个用于访问配置文件的 api。请参阅我的答案中的代码以了解一种方法。您不必求助于将其作为 xml 文件读取。

以上是关于默认事务超时的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中,默认的最大事务超时是多少

Hibernate:相对于自定义 @Transactional(timeout) 的默认事务超时

JBoss事务超时设置?

JBoss事务超时设置?

使用 wildfly CLI 可以增加应用程序级别的事务超时吗?

设置mysql 事务锁超时时间 innodb_lock_wait_timeout