从报错“无效操作,连接被关闭”探究Transaction的Timeout超时机制

1、报错如下:Invalid Operation the connection is closed,无效操作,连接被关闭。这个错误是并不是每次都报,只有在复杂操作、大事务的情况下才偶然报出来。

stackOverflow上有很多关于这个问题的讨论,例如这个:《System.Data.OracleClient random Invalid Operation the connection is closed》,但较零散,全扫了一遍之后,我仍然有如下疑问:

1)怎么看TransactionScope里的Timeout到底是多少,比如通过TransactionOptions.Timeout = new TimeSpan(0,0,3)设置之后,怎么知道TransactionScope里的超时就是3s?

2)默认MaxTimeout=10m,怎么才能设置任意值?

3)嵌套事务的外层超时是否包括所有内层事务的时间?

4)超时机制是怎么起作用的?

通过Reflector之类的工具查看源码,终于有了初步的理解,不对的地方,请大家指正!

2、怎么看TransactionScope里的Timeout?

用调试器逐级展开TransactionScope实例如下:

scope->committableTransaction->base->internalTransaction->absoluteTimeout //注:这是展开过程,不是代码

这个absoluteTimeout就是实际结果,但往往与你设置的值不匹配,比如:

TimeSpan absoluteTimeout
3s 5
10s 19
1m 117
10m 1171
30m 3515
1h 7031

看起来是经过某个算法转换后的值,这个算法写在TransactionTable.TimeoutTicks()里:

internal long TimeoutTicks(TimeSpan timeout){
  if(timeout != TimeSpan.Zero) {
    return (timeout.Ticks / 10000L >> 9) + this.ticks;
  }
  return 9223372036854775807L;
}

这就清楚了,再加上上面那张对照表,就可以通过absoluteTimeout清楚知道设置是否生效。

3、默认MaxTimeout=10m,怎么才能设置任意值?

1)先说一下这个10m怎么来的?

TransactionScope.ctr()->TransactionManager.ValidateTimeout()->MaximumTimeout->MachineSettingsSection.MaximumTimeout

这个属性先读取c:\windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config里的值://注意对应的framework的版本!

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

当然,我查看下来,所有版本的machine.config里默认都没有这个节点。那么退一步,由Attribute设置默认值:

[ConfigurationProperty("maxTimeout", DefaultValue = "00:10:00")]
public TimeSpan MaxTimeout

2)再说一下怎么改成任意值?

2.1)修改machine.config,优点:方便,缺点:会影响机器上的所有事务。方法是在全局的machine.config里添加对应节点,注意在自己的app/web.config里添加<machineSettings>节点会报错。

2.2)用反射(神器)!优点:只作用于自己的事务,缺点:用反射、稍麻烦、稍慢。

static void ChangeMaximumTimeout() {
 Type t = typeof(TransactionManager);
 FieldInfo f = t.GetField("_cachedMaxTimeout", BindingFlags.NonPublic | BindingFlags.Static);
 f.SetValue(null, true);
 f = t.GetField("_maximumTimeout", BindingFlags.NonPublic | BindingFlags.Static);
 f.SetValue(null, new TimeSpan(2, 0, 0));
}

这么写是因为最终大家取的都是static类里的static属性:

public static class TransactionManager {
 public static TimeSpan MaximumTimeout {
  get {
   if(!_cachedMaxTimeout) {
     _maximumTimeout = MachineSettings.MaxTimeout;
   }
   return _maximumTimeout; }}}

贴出来,一目了然!

4、嵌套事务的外层超时是否包括所有内层事务的时间?

我理解外层超时包含所有内层事务的执行时间,测试代码如下:

option.Timeout = new TimeSpan(0,0,3);
using(var scope = new TransactionScope(TransactionScopeOption.Required, option)) {
 Thread.Sleep(2000);

 option1.Timeout = new TimeSpan(0,0,5);
 using(var scope1 = new TransactionScope(TransactionScopeOption.Required, option)) {
  Thread.Sleep(500); // 800以上基本就报超时错误了
}}

5、超时机制是怎么起作用的?

1)对于非根(committableTransaction == null)的事务,会构造一个scopeTimer = new Timer(timeSpan, TimeoutCallback)来触发超时回滚;

2)对于committableTransaction != null的根事务,超时机制尚未找到,有待补充完整。

时间: 2024-10-06 12:34:32

从报错“无效操作,连接被关闭”探究Transaction的Timeout超时机制的相关文章

VMware报错:无法连接 MKS: 套接字连接尝试次数太多;正在放弃

环境: win10    VMware pro 14   Cent OS 7 问题详情: 报错:无法连接 MKS: 套接字连接尝试次数太多:正在放弃 解决方案: 1.关闭报错的虚拟机 2.打开控制面板->系统和安全->管理工具->服务 3.找到VMware Authorization Service,鼠标右键选择启动,然后就可以看到状态的改变 4.选中后鼠标右键属性中启动类型设置为自动.下次就会自启动 5.重新打开虚拟机,测试 原文地址:https://www.cnblogs.com/s

postgreSql 报错 (psycopg2.errors.IdleInTransactionSessionTimeout) terminating connection due to idle-in-transaction timeout 解决

具体问题: 第二个问题呢就是 原因大概是酱紫的 在mysql超过wait_timeout后,连接会挂掉,服务就会报错 OperationalError: (_mysql_exceptions.OperationalError) (2006, 'MySQL server has gone away') ,由于也sqlalchemy关闭了autocommit,隐式使用了事务,还会有错误StatementError: (sqlalchemy.exc.InvalidRequestError) Can't

magento后台登陆被锁定 索引报错的解决:General error: 1205 Lock wait timeout

1. magento在索引的时候用shell,有时候会报错: General error: 1205 Lock wait timeout exceeded 这个时候,是因为行锁的原因,在表中您直接用sql执行更新,会报这个错,也就是说这个错是mysql报的. 需要吧表index_process解锁 如果您想快速的解决,那么,把表导入,修改,删除数据库中index_process表,重新导入,OK,行锁会消失. 网上也有把index的mode改为手动,索引完改回来,好像还是有问题,报这个错就是my

解决打印机报错:操作无法完成(错误0x00000709)。

解决:操作无法完成(错误0x00000709).再次检查打印机名称,并确保打印机已连接到... 上午同时说,网络打印机打印不了,于是首先看一下打印服务器IP是不是给换了,结果没换. 接着尝试重新添加一下网络打印机,结果问题来了,连不上,提示: 操作无法完成(错误0x00000709).再次检查打印机名称,并确保打印机已连接到网络.(xp系统本人机器提示) 操作无法完成.键入的打印机名不正确,或者指定的打印机没有连接到服务器上.有关详细信息,请单帮助 然后网上查了查资料,说法倒有N多,说什么看看打

【记录】java 阿里oss频繁上传文件报错:网络连接错误,详细信息:Connection pool shut down

问题解析:由于在创建连接的时候@Bean默认是单例的,所以当我们每次上传完后,连接关闭,导致再次上传出现连接错误 解决方式:将bean设置成多例模式 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE ) 参考资料:https://www.cnblogs.com/IT-study/p/11358832.html 参考资料:https://www.jianshu.com/p/90063e263971 希望能帮助到大家! 原文地址:https

CITRIX安装成功后,通过CPS调用应用程序报错500无法连接LICENSE服务器解决方法

原因分析:安装的CPS服务器版本与FARM版本不一致导致的. 解决方法: 打开对应CPS的CITRIX客户端界面,选中当前对应SERVER,右键"所有任务"---SET SERVER EDIDTION-修改为铂金版问题解决.

wuzhicms页面报错 Notice 错误,如何关闭错误显示!

错误类型类似: PHP Notice:  Use of undefined constant E_DEPRECATED - assumed 'E_DEPRECATED' in D:\freehost\394786283a1\web\coreframe\core.php on line 18 打开文件:www/configs/web_config.php

NPOI读取Excel报错:无法访问已关闭的流或文件

input = new FileInputStream(fileName); Workbook wb = (Workbook) (isExcel2003 ? new HSSFWorkbook(input) : new XSSFWorkbook(fileName)); 上面的这个写法input不能close以及删除 下面这种写法即可HSSFWorkbook wb2003 = null;XSSFWorkbook wb2007 = null;if(isExcel2003){wb2003 = new H

nginx关闭php报错页面显示

默认情况下nginx是会显示php的报错的,如果要关闭报错显示,需要在php-fpm.ini文件里面设置,貌似默认情况下在php.ini关闭没效果, 如下设置就可以了: ;php_flag[display_errors] = off php_admin_value[error_log] = /data/www/log/error.log php_admin_flag[log_errors] = on 如果没有生效,查看下phpinfo()输出的结果中,display_errors,error_l