关于SqlTransaction.Connection
最近客户反应一个测试项目运行速度有时会很慢,并隅尔会出现IIS连接数过多的错误,目前项目的使用人数并不多,怎么会有连接数过多的问题呢?难道是数据库哪里连接没关闭了,于是查看了代码,感觉都有关闭了啊。后来多次调试之后,终于发现问题了。
数据的底层连接是以前一个同事自己写的一个简单的框架,在他的一个底层类里面有这样一个方法:
1 /// <summary>
2 /// 创建一个SqlTransaction(用于事务)
3 /// </summary>
4 /// <returns></returns>
5 public SqlTransaction GeneratedTrans()
6 {
7 SqlConnection conn = new SqlConnection(this.sqlConnectionString);
8 conn.Open();
9 return conn.BeginTransaction();
10 }
这是获取一个事务SqlTransaction的方法,其实之前在用他这个方法的时候,就感到有点奇怪了,为什么将SqlConnection作为这个方法的内部成员了呢?到时用完这个事务之后,怎么关闭这个SqlConnection啊?但是当时那个同事已经离职了,我也不敢随便去改他底层的东西,并且发现,SqlTransaction类有个Connection的属性,于是乎很自然地认为这个Connection应该就是里面的SqlConnection了,所以在使用完这个事务之后,加上了以下代码:
if (trans != null && trans.Connection != null && trans.Connection.State == ConnectionState.Open)
trans.Connection.Close();
一直都以为这样已经就可以了,直到这次,在调试中发现,当代码执行到这里的时候,trans.Connection居然为空,那是不是表示,创建这个SqlTransaction的那个SqlConnection已经关闭,并且已被设为空了呢。我试着将GeneratedTrans方法里面的conn对象放到方法外面,作为类的一个全局变量,然后加多一个方法:
1 /// <summary>
2 /// 关闭连接
3 /// </summary>
4 public void CloseConnection()
5 {
6 if(conn != null){
7 if (conn.State == ConnectionState.Open)
8 conn.Close();
9 }
10 }
最后在
if (trans != null && trans.Connection != null && trans.Connection.State == ConnectionState.Open)
trans.Connection.Close();
下面调用这个方法,再次调试,发现,当代码执行到上面代码段时,trans的Connection已经为空了,之后跳进CloseConnection方法里面,发现conn不为空,并且状态是打开的,原来最终Connection还是没有关闭到啊。那SqlTransaction的Connection属性难道不是创建它的那个SqlConnection?查了一下MSDN,它的描述为:
获取与该事务关联的 SqlConnection 对象,或者如果该事务不再有效,则为 null 引用(在 Visual Basic 中为 Nothing)。
重点就在后面那句:如果该事务不再有效,则为 null 引用。当事务提交以后,此事务已经不再有效,所以自动将它的SqlConnection属性设为空了,但对于创建它的SqlConnection依然存在,并没有关闭到。这次想不改他的东西都不行了,连忙修改过来,好在要修改的代码并不多,要不然真要死人了。
不知道有没有新手也犯过这样的错,有的赶紧改过来吧,不过我想应该没什么人会这样关闭连接吧,呵呵。