由于一个未按预期提交的事物导致的阻塞的解决办法

http://blog.sina.com.cn/s/blog_7b8b13080102v50t.html

 由一个未按预期提交的事务导致的阻塞,其特征就是问题连接早就进入了空闲状态,但是,如果检查sysprocesses.open_tran,就会发现他不为0,事务还没有被提交。这类问题很多都是因为应用遇到了一个执行超时,或者其他愿意,使得要执行的语句被提前终止了,但是连接还保留着。应用没有处理好这个意外情况,发出事务提交或者回滚指令,导致一个事务被遗留在SqlServer里。

      遇到这类问题,许多使用者会误认为是SqlServer端没有处理好。其实,执行超时(command timeout)完全是一个客户端的行为。当客户端应用向SqlServer发来语句执行请求时,自己会有一个执行超时设置。一般ADO或SDO.NET的连接默认超时时限是30S。如果30S以内SqlServer没有完成语句但会任何结果,客户端就会发送一个Attention的消息给SqlServer。告诉SqlServer他不想继续等下去。SqlServer收到这个消息后,会终止当前正在隐形的语句(或批处理)。但是,为了维护客户端的逻辑,SqlServer默认不会自动回滚或提交这个连姐已经打开的事务,而是等待客户端的后决定。如果客户端不发来回滚或提交指令,SqlServer会永远把这个事务保持下去,直到客户端主动断开连接为止。

     当碰上这样的情况,也有相应的解决办法:

(1)在做SqlServer调用的时候,必须加上错误捕捉和处理语句。
     SqlServer客户端程序(包括ODBC和OLE_DB)当语句执行遇到意外终止(包括超时)的时候,都会向应用返回错误信息。客户端在捕捉到错误信息后时,除了做记录以外(这对问题定向非常有帮助),还要运行下面这句话,把没有提交的事务回滚掉。
IF @@TRANCOUNT > 0 ROLLBACK TRAN
有些程序员会问,我在T-SQL批处理里已经写了T-SQL层面的错误捕捉和处理语句,(IF@@ERROR<>0 ROLLBACK TRAN),还有必要让应用程序再做一遍么?需要意识到的是,有些异常(比如超时)终止是整个T-SQL批处理的执行,而不仅仅是当前语句,所以,当这些异常发生时,T-SQL层面的所悟捕捉和处理很可能也一起被取消了。他们不能发挥想象中的作用。在应用程序里的错误步骤和处理语句是必不可少的。
(2)设置连接属性“SERT XACT_ABORT ON”。
    当SERT XACT_ABORT 为ON时,如果执行T-SQL语句产生运行错误,则整个事务将终止并回滚、。当SERT XACT_ABORT 为OFF时,处理方法不是唯一的。有时只回滚产生错误的T-SQL语句,而事务将继续进行处理。如果错误很严重,即使SERT XACT_ABORT 为OFF,也可能回滚整个事务。OFF是默认设置。如果没有办法很快规范应用程序的错误捕捉和处理语句,一个最快的办法就是在每个连接建立以后,或者是最容易出现问题的存储过程开头,运行“SERT XACT_ABORT ON”,让SqlServer帮助应用程序回滚事务。
 (3)考虑是否要关闭连接池。
    一般的SqlServer应用都会使用连接池来得到良好的性能。如果有一个连接忘记把事务关闭就退出连接,那么这个链接会被还给连接池,但是这个时候,事务不会马上被清理掉,客户端驱动程序会在这个连接下一次被重用的时候(又有新的用户要建立连接),发一句sp_reset_connection命令清理当前连接上次遗留下来的所有对象,包括回滚未提交的事务。如果连接交还给连接池以后很久都没有被重用,那他的事务就会持续很长时间,引起阻塞。有些Java程序使用的驱动程序,提供连接功能,但是不提供连接冲重用时的事务清理功能。这样的连接池对对应用开发质量要求很高,稍不注意,就会容易发生阻塞。
    如果不能很快实施建议(1)、(2),把连接池关闭能缩短事务持续的时间,也从一定程度上缓解阻塞问题。

猜你喜欢

转载自blog.csdn.net/newtelcom/article/details/79816407