System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?

时间:2021-04-18 03:36:58
如果 System.Data.SQLClient.SqlConnection(下面简称dbconn)不及时Close,那么造成的后果可以在这里看到: http://www.cnblogs.com/juqiang/archive/2005/12/10/294269.html

具体的原因,我们来看代码(用reflector反编译.net framework 2.0的dll)

dbconn有一个方法叫做:Open,部分代码如下:
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?  try
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         {
 3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            statistics = SqlStatistics.StartTimer(this.Statistics);
 4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            this.InnerConnection.OpenConnection(this, this.ConnectionFactory);
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            SqlInternalConnectionSmi innerConnection = this.InnerConnection as SqlInternalConnectionSmi;
 6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            if (innerConnection != null)
 7System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            {
 8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                innerConnection.AutomaticEnlistment();
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            }

10 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
注意上面的第4行, this .InnerConnection.OpenConnection( this this .ConnectionFactory);这里的this.ConnectionFactory是一个DbConnectionFactory类型,定义在class SqlConnection中
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?static  SqlConnection()
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    EventInfoMessage 
= new object();
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    _connectionFactory = SqlConnectionFactory.SingletonInstance;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    ExecutePermission = CreateExecutePermission();
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
在看第一段代码的第4行,这里用InnerConnection来进行OpenConnection,那么InnerConnection的类型,我们可以从下面看到:
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?public  SqlConnection()
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
this.ObjectID = Interlocked.Increment(ref _objectTypeCount);
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    GC.SuppressFinalize(
this);
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
this._innerConnection = DbConnectionClosedNeverOpened.SingletonInstance;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
它是一个DbConnectionClosedNeverOpened类型(具体做啥的,我们不管),它的基类是:DbConnectionClose。ok,确定好上述两个类型后,我们就看一下OpenConnection的代码:(class DbConnectionClosed)
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?   try
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         {
 3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            connectionFactory.PermissionDemand(outerConnection);
 4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            to = connectionFactory.GetConnection(outerConnection);
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        }

 6 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         catch
 7 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         {
 8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            connectionFactory.SetInnerConnectionTo(outerConnection, this);
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            throw;
10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        }
看一下第4行,哈,这里绕到了我们上面的conn factory,我们看它里面的GetConnection怎么写的?(class DbConnectionFactory)
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?internal  DbConnectionInternal GetConnection(DbConnection owningConnection)
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close? {
 3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    DbConnectionInternal connection;
 4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    DbConnectionPoolGroup connectionPoolGroup = this.GetConnectionPoolGroup(owningConnection);
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    DbConnectionPool connectionPool = this.GetConnectionPool(owningConnection, connectionPoolGroup);
 6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    if (connectionPool == null)
 7System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    {
 8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        connectionPoolGroup = this.GetConnectionPoolGroup(owningConnection);
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        connection = this.CreateNonPooledConnection(owningConnection, connectionPoolGroup);
10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        this.PerformanceCounters.NumberOfNonPooledConnections.Increment();
11System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        return connection;
12System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

13System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    connection = connectionPool.GetConnection(owningConnection);
14System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    if (connection == null)
15System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    {
16System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        Bid.Trace("<prov.DbConnectionFactory.GetConnection|RES|CPOOL> %d#, GetConnection failed because a pool timeout occurred.\n"this.ObjectID);
17System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        throw ADP.PooledOpenTimeout();
18System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

19System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    return connection;
20System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
注意第5行里面的GetConnectionPool的调用,继续看它内部的代码:(class DbConnectionFactory)
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?private  DbConnectionPool GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup)
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close? {
 3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    if (connectionPoolGroup.IsDisabled && (connectionPoolGroup.PoolGroupOptions != null))
 4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    {
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        Bid.Trace("<prov.DbConnectionFactory.GetConnectionPool|RES|INFO|CPOOL> %d#, DisabledPoolGroup=%d#\n"this.ObjectID, connectionPoolGroup.ObjectID);
 6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        DbConnectionPoolGroupOptions poolGroupOptions = connectionPoolGroup.PoolGroupOptions;
 7System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        DbConnectionOptions connectionOptions = connectionPoolGroup.ConnectionOptions;
 8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        string connectionString = connectionOptions.UsersConnectionString(false);
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        connectionPoolGroup = this.GetConnectionPoolGroup(connectionString, poolGroupOptions, ref connectionOptions);
10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        this.SetConnectionPoolGroup(owningObject, connectionPoolGroup);
11System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

12System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    return connectionPoolGroup.GetConnectionPool(this);
13System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
注意第9行,我们go on...(Class DbConnectionFactory)
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         if  ((poolOptions  ==   null &&  ADP.IsWindowsNT)
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?         {
 3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            if (group != null)
 4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            {
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                poolOptions = group.PoolGroupOptions;
 6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            }

 7System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            else
 8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            {
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                poolOptions = this.CreateConnectionPoolGroupOptions(options);
10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?            }

11System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        }

12 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
依然是第9行(枯燥的数字。。。),继续往里面看:(Class DbConnectionFactory)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?protected   override  DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions connectionOptions)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    SqlConnectionString str 
= (SqlConnectionString) connectionOptions;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
if (str.ContextConnection || !str.Pooling)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        
return null;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
int connectTimeout = str.ConnectTimeout;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
if ((0 < connectTimeout) && (connectTimeout < 0x20c49b))
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        connectTimeout 
*= 0x3e8;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
else if (connectTimeout >= 0x20c49b)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        connectTimeout 
= 0x7fffffff;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
return new DbConnectionPoolGroupOptions(str.IntegratedSecurity, str.MinPoolSize, str.MaxPoolSize, connectTimeout, str.LoadBalanceTimeout, str.Enlist, false);
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
看最后一行,调用了一个new操作,注意里面的参数!有MaxPoolSize,MinPoolSize等属性。而这些重要属性是从str,即SqlConnectionString的一个property(Class DbConnectionPool,快到终点了,坚持一下。。。)
  1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?internal  SqlConnectionString( string  connectionString) :  base (connectionString, GetParseSynonyms(),  false )
  2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close? {
  3System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    bool inProc = InOutOfProcHelper.InProc;
  4System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._integratedSecurity = base.ConvertValueToIntegratedSecurity();
  5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._async = base.ConvertValueToBoolean("asynchronous processing"false);
  6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._connectionReset = base.ConvertValueToBoolean("connection reset"true);
  7System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._contextConnection = base.ConvertValueToBoolean("context connection"false);
  8System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._encrypt = base.ConvertValueToBoolean("encrypt"false);
  9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._enlist = base.ConvertValueToBoolean("enlist", ADP.IsWindowsNT);
 10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._mars = base.ConvertValueToBoolean("multipleactiveresultsets"false);
 11System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._persistSecurityInfo = base.ConvertValueToBoolean("persist security info"false);
 12System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._pooling = base.ConvertValueToBoolean("pooling"true);
 13System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._replication = base.ConvertValueToBoolean("replication"false);
 14System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._userInstance = base.ConvertValueToBoolean("user instance"false);
 15System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._connectTimeout = base.ConvertValueToInt32("connect timeout", 15);
 16System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._loadBalanceTimeout = base.ConvertValueToInt32("load balance timeout"0);
 17System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._maxPoolSize = base.ConvertValueToInt32("max pool size", 100);
 18System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._minPoolSize = base.ConvertValueToInt32("min pool size"0);
 19System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    this._packetSize = base.ConvertValueToInt32("packet size"0x1f40);
===============================其他代码省略========================================
181System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }
182System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
这段代码很长,但是我们注意上面的第17行,这里有一个默认值100,就是说,如果你没有在connection string中指定max pool size,那么该值就是100。
那么,如果我们代码中对于dbconn进行了Open,没有进行Close,conn pool就会一直增长,一直涨到100,涨到这个Max Pool Size。原因我们看下面:(Class DbConnectionPool)
 1 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?             case   2 :
 2 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                Bid.PoolerTrace( " <prov.DbConnectionPool.GetConnection|RES|CPOOL> %d#, Creating new connection.\n " this .ObjectID);
 3 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                 try
 4 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                 {
 5System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                    fromTransactedPool = this.UserCreateRequest(owningObject);
 6System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                }

 7 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                 catch
 8 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                 {
 9System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                    if (fromTransactedPool == null)
10System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                    {
11System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                        Interlocked.Decrement(ref this._waitCount);
12System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                    }

13System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                    throw;
14System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?                }

15 System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
注意上面的第5行,UserCreateRequest,看这个方法:
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?private  DbConnectionInternal UserCreateRequest(DbConnection owningObject)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    DbConnectionInternal internal2 
= null;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
if (this.ErrorOccurred)
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        
throw this._resError;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
if ((this.Count >= this.MaxPoolSize) && (this.MaxPoolSize != 0))
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    {
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        
return internal2;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
if (((this.Count & 1!= 1&& this.ReclaimEmancipatedObjects())
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
{
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?        
return internal2;
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    }

System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?    
return this.CreateObject(owningObject);
System.Data.SQLClient.SqlConnection在Open之后为什么需要及时Close?}
上面的代码很清楚的表明,如果count>=MaxPoolsize,会返回一个internal2,而这个field是一个Null!从其他的地方,我们也能找到类似的判断。

上面写了这么多,结论就是,如果dbconn在Open之后,没有Close,那么会造成conn个数上涨,到100之后就会停下来。第101个链接的请求,是无法创建成功的。这样,db和web server很可能都是CPU很低,如0%,但是客户端的响应时间就是很长,造成性能下降。