连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法

本文出处:http://www.cnblogs.com/wy123/p/6110349.html

之前遇到过这么一种情况:

  连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持续较长时间,有时间持续时间较短,没有什么规律。
   之后分析相关存储过程和代码写法,发现是存储过程中开启了事务,而应用程序在调用存储过程发生异常之后没有进行特别的处理(提交或者回滚),
   那么在执行方法发生异常之后,连接关闭了,但是数据库中遗留有活动事务(dbcc opentran对应的SessionId是sleeping状态),于是就产生了阻塞。
   关键是活动事务会不定时自己消失,就有点诡异了,这是本文的重点。

这种机制跟连接池有关:

当应用程序连接数据库的时候开启了连接池,如果应用程序调用了一个开启了事务操作的存储过程,
当发生异常的时候,有可能会出现数据库连接关闭,而存储过程中的事务既没有提交,也没有回滚的情况
这种情况下就会产生“孤立事务”,也就是说,因为打开事务的数据量连接断掉了,而事务还处于活动状态,
实际上开启连接池的情况下,数据库连接的关闭,并不是物理上的关闭,而是将数据库连接返回到连接池。
此时如果没有外界的干预,包括没有对这个数据库连接没有被重用,或者这个连接没有物理断开,或者是没有重启应用程序,或者没有数据库服务器,这个事务将一直持续下去。
因为活动事务将阻塞其他Session对相关表的排他性访问,所以就表现为阻塞。

如何判断是否发生了连接池中的连接重用

首先,一个连接数据库的过程中,有没有重用连接池中的连接,在SQL Server中有哪些区别?
以ado.net为例,如果在连接字符串中加入pooling=false;则表示不启用连接池.
如下,连续执行两次数据库访问,两次数据库访问均在连接字符串中加入了pooling=false;表示不启用连接池

  

  如下是观察到profile中的连接动作,注意这里第一次连接断开之后,有一个logout,第二次访问数据的时候,有一个login

  

  如果将上述两个方法中连接字符串中的pooling=false;改为pooling=true;再次连续执行两个方法,
  会发现第二次连接数据的之前,也即在第一个logout之后,第二次login之前,有一个exec sp_reset_connection的动作。
  exec sp_reset_connection的执行标志着连接从连接池中重用了连接,关于这个动作的作用下面再说

什么情况下会出现数据库连接关闭,而事务保持活动状态 

  首先,参考如下截图,编写一个事务性存储过程,用waitfor delay ‘00:00:50‘的方式延长其事务提交时间,造成连接超时(默认ado.net连接30秒)

在ado.net中调用这个存储过程,连接超过30秒之后超时异常,当前执行方法的数据库连接被关闭,此时并不关闭Visual Studio,模拟应用程序并没有终止

  

  此时查询数据中的活动事务,发现有一个活动事务,活动事务是上次执行“TimeoutFunction”造成的,
  但此时“TimeoutFunction”发生了异常,数据库连接被正常关闭,  
  此时,执行这个方法造成的事务还是活动状态的,如下截图

而此时观察SessionId = 57的状态,他是sleeping啊,已经开始呼呼睡大觉了。

如果此时对事务中的表执行查询操作,会发现是被阻塞的,事实上t1这张表在上述方法执行之前一行数据都没有

数据库连接被重用,第一次连接遗留在数据库中的事务被回滚

  上面在执行第一个方法之后,并没有中断VS的调试状态,我们继续执行第二个方法,此时第二个方法会重用第一个方法的数据库连接,
  至于为什么说他就重用了第一个方法的数据库连接,一开始就说了。
  当执行exec sp_reset_connection的时候,活动事务被回滚。查询能够正常执行。如下截图

  查询在exec sp_reset_connection之后正常完,因为事务是被回滚的,所以t1表没有任何数据

  上述示例就模拟出来类似这么一种场景,当连接字符串中开启了连接池之后
  一个方法执行超时连接被关闭之后,其调用的存储过程中的事务并没有显式的提交或者回滚,造成连接关闭而事务继续保持活动状态的情况
  比如web程序,一个方法执行完成之后,连接超时但是正常关闭(归还连接池),事务保持活动状态,
  此时web服务器并没有停止下来,也就是应用程序没有直接关闭,也就是类似于Visual Studio继续保持DEBUG状态,
  此时事务一直保持活动状态知道连接被重用(或者应用程序被关闭),那么其他Session发起对活动事务锁定的对象,就会发生阻塞。
  问题就出在这里,主观上无法保证连接池中的那个连接什么时候被重用,也就无法保证活动事务要持续多久,
  如果活动事务一直保持,那么阻塞就一直保持,这显然是不可接受的

关于sp_reset_connection的作用,我就懒得打字了,参考《Microsoft SQL Server企业级平台实践》第316页

如何避免连接关闭而事务保持活动

  1,本质因为存储过程执行时间超过了连接的时间导致连接关闭的,那么就可以从分析事务性操作超时的原因入手。

  2,可以在应用程序的代码中catch的中,进行异常处理时候,保证连接关闭之前,活动事物最终提交或者回滚(作出明确的处理)

  3,关闭连接池,这种情况下,任何被关闭的数据库连接,其发起的事务都将被回滚,但连接池也是为了提交数据性能,可行性不大。

  4,从性能上以及连接池机制中分析,也只能缓解这个问题,而逃不过这个问题,
    实际上,面对连接超时断开而是事务继续保持活动状态这种情况,在存储过程的事务性操作中加入try catch也是无济于事的,
    那么就可以使用SET XACT_ABORT ON;命令,确保在任何异常情况下,对事务进行回滚。关于XACT_ABORT可参考联机丛书。

    

时间: 2024-10-27 19:31:48

连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法的相关文章

join时显示no join predicate原因分析以及解决办法

本位出处:http://www.cnblogs.com/wy123/p/6238844.html 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据,因为预期很快就可以查询出来结果的SQL,实则半个小时都出不来,后面会有截图 观察执行计划的时候发现中间有一步中出现一个类似如下非常规的连接提示警告,如下图 no join predicate 意思就是没有连接谓词,表之间join的时候没有指定连接谓词可以导致no join predicate, 但是

Activiti+oracle 启动项目时不能自动建表或更新表的问题分析及解决办法

现象描述:按照正常配置,第一次启动时不能自动建表 关键配置片段如下: <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource" /> <property name=&q

点击ViewGroup时其子控件也变成pressed状态的原因分析及解决办法

这个问题,当初在分析touch事件处理的时候按理应该分析到的,可是由于我当时觉得这块代码和touch的主题不是那么紧密, 就这么忽略掉了,直到后来在这上面遇到了问题.其实这个现象做Android开发的应该或多或少的都遇到过,我在我们自己的app中 也发现了这一现象,当初是百思不得其解,因为按照我自己的研究.分析,只有在一个view接受按下的touch事件时,才会调到view 自己的setPressed方法,从而改变background状态啊.这里的case明显没有按下这个子view啊,按下的是V

VC_ADO连接SQLSERVER时连接字符串的模式

一.连接SQL SERVER的第一种连接字串: 是针对数据库身份验证模式为"SQL SERVER 和 windows"而言, 连接字串为: CString strConn; strConn = "Provider = SQLOLEDB.1;\ Persist Security Info = true;\ User ID = sa;\ Password=123456;\ Initial Catalog = tempdb;\ Data Source = 127.0.0.1&quo

[ArchLinux]进行更新时出现错误:GPGME error: 无数据,数据库无效的解决办法/

今天在我进行系统更新pacman -Syu时,出现了如下错误: # pacman -Syu 错误:GPGME error: 无数据 错误:GPGME error: 无数据 错误:GPGME error: 无数据 错误:GPGME error: 无数据 错误:GPGME error: 无数据 :: 正在同步软件包数据库... core 已经是最新版本 0.0 B 0.00B/s 00:00 [----------------------] 0% extra 已经是最新版本 0.0 B 0.00B/

详细!交叉编译时 note: the mangling of &#39;va_list&#39; has changed in GCC 4.4解决办法

为什么要在标题前面加了详细两个字,就是为了吸引看文章的你还有写文章的我这种小白,我是从坑里面爬出来了. 废话少说.... 问题就是这样子了,至于解决办法,在网上搜索了很久,大多数以一段英文作为解决办法,... I think that the warning is accurate; the mangling of va_list has indeed changed on ARM in GCC 4.4 in order to conform to the ARM ABI specificati

使用POI解析Excel时,出现org.xml.sax.SAXParseException: duplicate attribute &#39;o:relid&#39;的解决办法

1.使用org.apache.poi解析excle,.xlsx类型文件InputStream is = new FileInputStream(strFileName);XSSFWorkbook wb = new XSSFWorkbook(is);出现异常如下: org.apache.poi.POIXMLException: java.lang.reflect.InvocationTargetExceptionat org.apache.poi.xssf.usermodel.XSSFFactor

mysql数据库导入sql文件时提示“Error Code: 1153 - Got a packet bigger than &#39;max_allowed_packet&#39; bytes”解决办法

向mysql数据库中导入sql文件时,如果文件过大(几百M),会提示"Error Code: 1153 - Got a packet bigger than 'max_allowed_packet' bytes" 1.查看目前数据库配置 show VARIABLES like '%max_allowed_packet%'; 显示如下结果 +--------------------+---------+ | Variable_name      | Value   | +--------

使用webpack命令打包时,报错TypeError: Cannot read property &#39;presetToOptions&#39; of undefined的解决办法

我只安装了webpack,没有安装webpack-cli,第一次输入webpack打包时,提示 One CLI for webpack must be installed. These are recommended choices, delivered as separate packages: - webpack-cli (https://github.com/webpack/webpack-cli) The original webpack full-featured CLI. We wi