连接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可参考联机丛书。

总结:本文浅析了启用数据库连接池的条件下,在对数据库访问异常的情况下,造成孤立事物现象进行了原因进行了分析以及可行的解决方法尝试。
从中得到一个教训,就是在对数据访问异常处理的时候,应用程序中一定要确保连接与事物的同步释放。同时,对事务处理的时候,存储过程中一定要做到严谨的事务控制和异常处理机制。
确保在异常情况下,事务能够直接回滚,避免引起类似的阻塞。
连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法的更多相关文章
- SQLServer数据库中开启CDC导致“事务日志空间被占满,原因为REPLICATION”的原因分析和解决办法
本文出处:http://www.cnblogs.com/wy123/p/6646143.html SQLServer中开启CDC之后,在某些情况下会导致事务日志空间被占满的现象为:在执行增删改语句(产 ...
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- Nested Loops join时显示no join predicate原因分析以及解决办法
本文出处:http://www.cnblogs.com/wy123/p/6238844.html 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据, ...
- Activiti+oracle 启动项目时不能自动建表或更新表的问题分析及解决办法
现象描述:按照正常配置,第一次启动时不能自动建表 关键配置片段如下: <bean id="processEngineConfiguration" class="or ...
- 点击ViewGroup时其子控件也变成pressed状态的原因分析及解决办法
这个问题,当初在分析touch事件处理的时候按理应该分析到的,可是由于我当时觉得这块代码和touch的主题不是那么紧密, 就这么忽略掉了,直到后来在这上面遇到了问题.其实这个现象做Android开发的 ...
- sqlyog连接Linux上的mysql报错误号码2013,错误号码1130的解决办法
sqlyog连接Linux上的mysql报错误号码2013,错误号码1130的解决办法 1.报错误号码2013,可能是端口号不是默认的3306,需要改成对应的,检查命令是: [root@host et ...
- @PathVariable出现点号"."时导致路径参数截断获取不全的解决办法
@PathVariable出现点号"."时导致路径参数截断获取不全的解决办法 比如,我路径是/test/{name},name的值是1.2.3.4,后台用@PathVariable ...
- oracle执行update语句时卡住问题分析及解决办法
转载:http://www.jb51.net/article/125754.htm 这篇文章主要介绍了oracle执行update语句时卡住问题分析及解决办法,涉及记录锁等相关知识,具有一定参考价值, ...
- @Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法
上午花了大半天排查一个多数据源主从切换的问题,记录一下: 背景: 项目的数据库采用了读写分离多数据源,采用AOP进行拦截,利用ThreadLocal及AbstractRoutingDataSource ...
随机推荐
- “不给力啊,老湿!”:RSA加密与破解
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 加密和解密是自古就有技术了.经常看到侦探电影的桥段,勇敢又机智的主角,拿着一长串毫 ...
- Java 8五大主要功能为开发者提供了哪些便利?
两年前当Java 8发布后,立即受到了业界的欢迎,因为它大大提高了Java的性能.它独特的卖点是,顾及了编程语言的每一个方面,包括JVM(Java虚拟机)和编译器,并且改良了其它帮助系统. Java是 ...
- 前端学HTTP之日志记录
前面的话 几乎所有的服务器和代理都会记录下它们所处理的HTTP事务摘要.这么做出于一系列的原因:跟踪使用情况.安全性.计费.错误检测等等.本文将谥介绍日志记录 记录内容 大多数情况下,日志的记录出于两 ...
- Lambda
Lambda Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可作为参数传递或作为函数调用值返回的本地函数. Lambda 表达式对于编写 LI ...
- [C#] 简单的 Helper 封装 -- RegularExpressionHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Maven多模块,Dubbo分布式服务框架,SpringMVC,前后端分离项目,基础搭建,搭建过程出现的问题
现互联网公司后端架构常用到Spring+SpringMVC+MyBatis,通过Maven来构建.通过学习,我已经掌握了基本的搭建过程,写下基础文章为而后的深入学习奠定基础. 首先说一下这篇文章的主要 ...
- Activity之概览屏幕(Overview Screen)
概览屏幕 概览屏幕(也称为最新动态屏幕.最近任务列表或最近使用的应用)是一个系统级别 UI,其中列出了最近访问过的 Activity 和任务. 用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除 ...
- OpenGL ES: Array Texture初体验
[TOC] Array Texture这个东西的意思是,一个纹理对象,可以存储不止一张图片信息,就是说是是一个数组,每个元素都是一张图片.这样免了频繁地去切换当前需要bind的纹理,而且可以节省系统资 ...
- BZOJ 1006 【HNOI2008】 神奇的国度
题目链接:神奇的国度 一篇论文题--神奇的弦图,神奇的MCS-- 感觉我没有什么需要多说的,这里简单介绍一下MCS: 我们给每个点记录一个权值,从后往前依次确定完美消除序列中的点,每次选择权值最大的一 ...
- CYQ.Data V5 从入门到放弃ORM系列:教程 - MAction类使用
背景: 随着V5框架使用者的快速增加,终于促使我开始对整个框架编写完整的Demo. 上周大概花了一星期的时间,每天写到夜里3点半,终完成了框架所有功能的Demo. 同时,按V5框架名称空间的顺序,对每 ...