笔记69-徐 程序端意外情况下SQLSERVER端可能导致的问题

笔记69-徐 程序端意外情况下SQLSERVER端可能导致的问题

 1 --程序端意外情况下SQLSERVER端可能导致的问题:应用层事务未提交  例子使用VBScript语言写的程序
 2 --前面这种没有及时清理事务的事务是由TSQL语句开启的,他导致阻塞危害可能
 3 --还不会很大,因为连接池总会在下一次重用这个连接的时候将上一个事务回滚
 4 
 5 --但是,有些程序员(例如:老张)会在应用层直接控制事务。例如在ADO.NET里
 6 --可以对每个连接调用BeginTrans和CommitTrans方法,或者甚至直接调用
 7 --System.Transaction接口,发起发布式事务让SQLSERVER参与进来等。
 8 
 9 
10 --这样做的好处是:在应用层就能够有事务的特性,而不仅仅是SQLSERVER内部的事务
11 --可是这样做也是有风险的。如果应用程序由于意外因素或设计缺陷,在偶发的情况下
12 --只开启了事务而没有关闭事务,那SQLSERVER这里的事务处理就混乱了。一个事务
13 --可能会长时间得不到提交,有些看上去成功的指令到最后会被意外回滚。
14 
15 --使用应用层事务需要在每个连接里发送SET IMPLICIT_TRANSACTIONS ON到SQL
16 --应用层需要在结尾写上IF @@TRANCOUNT>0 COMMIT TRAN
17 
18 
19 --例子里面一共开了3个连接 ,
20 --由于连接2的应用程序没有提交事务(模拟程序崩溃),
21 --事务留在SQL里,连接3使用了一句
22 --IF @@TRANCOUNT>0 ROLLBACK TRAN
23 --使连接3回滚由于连接2的事务还没有提交
24 --sp_reset_connection不奏效
25 
26 --如果这种情况出现在生产环境里,后果会非常严重
27 
28 --1、事务的长度会非常长
29 --由于物理连接一直在被连接池重用,连接2遗留下来的事务可能始终得不到提交或回滚
30 --这样产生的阻塞持续时间会很长,最后可能不得不重启应用(强制清理连接池)
31 --或者重启SQLSERVER来解决
32 
33 
34 --2、意外的回滚
35 --对于连接2,可能程序还有机会捕捉到错误信息,找出应该运行的committrans指令
36 --为什麽没有执行。对于连接3,从应用逻辑来讲,和连接2没有任何关系。他的整个
37 --执行过程没有任何错误,最后也成功地关闭了连接。可是,因为他重用了连接2
38 --的物理连接,导致了最后在程序清理连接池的时候,把整个事务回滚,也就是说
39 --非但连接2做的修改被回滚,连接3做的修改也被回滚。这时连接2和连接3早已结束
40 --最终用户认为修改已经成功。而最后,这些修改都因为某个不能预料到的时间点回滚
41 --而丢失
42 
43 ------------------------------------总结-----------------------------------------------------
44 --连接池虽然能够减少物理连接登入登出,提供应用速度,降低SQLSERVER负荷,但是当
45 --应用端对意外处理不当时,会带来额外的阻塞和其他危害。所以应用程序开发人员
46 --一定要严格规范好程序,避免这类问题发生。从数据库角度出发,完全通过TSQL语句
47 --来管理事务是比较安全可靠的方法(存储过程)。如果一个应用决定要使用其他方法
48 --管理事务(不管是ADO事务还是MSDTC)都要慎重考虑。在程序关闭连接的时候,可能
49 --加一些额外的指令确保事务已经提交。
50 --如果程序使用了非TSQL的事务而带来问题,那么跟踪可能是件非常困难和痛苦的事情
51 --需要跟踪人员同时精通SQLSERVER和应用程序逻辑,通过阅读问题开始出现的时候
52 --抓到SQL Trace文件,慢慢分析问题究竟在哪一次连接调用里。如果条件不允许或
53 --时间紧迫,关闭连接池是最快的解决方法

 

posted @ 2013-07-29 09:12 桦仔 阅读(...) 评论(...)  编辑 收藏