ado.net鏈接池

ado.NET 中提供了鏈接池的功能,多數開發人員不多設置它,由於它是默認的。
界面設置以下圖:
 
關閉鏈接池也很簡單,在鏈接字符串以下:
Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;Pooling=False ;
但鏈接池的本質是什麼樣的呢?
 
Reflector ,打開System.Data.SqlClient.SqlConnection ConnectionString 屬性的設置值的方法,以下:
private void ConnectionString_Set(string value)
{
    DbConnectionOptions userConnectionOptions = null;
    DbConnectionPoolGroup group = this.ConnectionFactory.GetConnectionPoolGroup(value, null, ref userConnectionOptions);
    DbConnectionInternal innerConnection = this.InnerConnection;
    bool allowSetConnectionString = innerConnection.AllowSetConnectionString;
    if (allowSetConnectionString)
    {
        allowSetConnectionString= this.SetInnerConnectionFrom(DbConnectionClosedBusy.SingletonInstance, innerConnection);
        if (allowSetConnectionString)
        {
            this._userConnectionOptions = userConnectionOptions;
            this._poolGroup = group;
            this._innerConnection = DbConnectionClosedNeverOpened.SingletonInstance;
        }
    }
    if (!allowSetConnectionString)
    {
        throw ADP.OpenConnectionPropertySet("ConnectionString", innerConnection.State);
    }
    if (Bid.TraceOn)
    {
        string str = (userConnectionOptions != null) ? userConnectionOptions.UsersConnectionStringForTrace() : "";
        Bid.Trace("<prov.DbConnectionHelper.ConnectionString_Set|API> %d#, '%ls'\n", this.ObjectID, str);
    }
}
再鏈接 到紅色的GetConnectionPoolGroup 方法,以下代碼
 internal DbConnectionPoolGroup GetConnectionPoolGroup(string connectionString, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions)
{
    DbConnectionPoolGroup group;
    if (ADP.IsEmpty(connectionString))
    {
        return null;
    }
    if (!this._connectionPoolGroups.TryGetValue(connectionString, out group) || (group.IsDisabled && (group.PoolGroupOptions != null)))
    {
        DbConnectionOptions options = this.CreateConnectionOptions(connectionString, userConnectionOptions);
        if (options == null)
        {
            throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing);
        }
        string str = connectionString;
        if (userConnectionOptions == null)
        {
            userConnectionOptions = options;
            str = options.Expand();
            if (str != connectionString)
            {
                return this.GetConnectionPoolGroup(str, null, ref userConnectionOptions);
            }
        }
        if ((poolOptions == null) && ADP.IsWindowsNT)
        {
            if (group != null)
            {
                poolOptions = group.PoolGroupOptions;
            }
            else
            {
                poolOptions = this.CreateConnectionPoolGroupOptions(options);
            }
        }
        DbConnectionPoolGroup group2 = new DbConnectionPoolGroup(options, poolOptions) {
            ProviderInfo = this.CreateConnectionPoolGroupProviderInfo(options)
        };
        lock (this)
        {
            Dictionary<string, DbConnectionPoolGroup> dictionary = this._connectionPoolGroups;
            if (!dictionary.TryGetValue(str, out group))
            {
                Dictionary<string, DbConnectionPoolGroup> dictionary2 = new Dictionary<string, DbConnectionPoolGroup>(1 + dictionary.Count);
                foreach (KeyValuePair<string, DbConnectionPoolGroup> pair in dictionary)
                {
                    dictionary2.Add(pair.Key, pair.Value);
                }
                dictionary2.Add(str, group2);
                this.PerformanceCounters.NumberOfActiveConnectionPoolGroups.Increment();
                group = group2;
                this._connectionPoolGroups = dictionary2;
            }
            return group;
        }
    }
    if (userConnectionOptions == null)
    {
        userConnectionOptions = group.ConnectionOptions;
    }
    return group;
}
TryGetValue 是判斷是否存在鏈接字符串爲connectionString 的鏈接,存在返回到group ,不存在就調用CreateConnectionOptions 建立一個DbConnectionOptions ,最後用
lock (this)
        {
            Dictionary<string, DbConnectionPoolGroup> dictionary = this._connectionPoolGroups;
            if (!dictionary.TryGetValue(str, out group))
            {
                Dictionary<string, DbConnectionPoolGroup> dictionary2 = new Dictionary<string, DbConnectionPoolGroup>(1 + dictionary.Count);
                foreach (KeyValuePair<string, DbConnectionPoolGroup> pair in dictionary)
                {
                    dictionary2.Add(pair.Key, pair.Value);
                }
                dictionary2.Add(str, group2);
                this.PerformanceCounters.NumberOfActiveConnectionPoolGroups.Increment();
                group = group2;
                this._connectionPoolGroups = dictionary2;
            }
            return group;
        }
這段代碼放到鏈接池中,在這裏,可能顯示的看到,ado.NET 的鏈接池實質上是一個Dictionary<string, DbConnectionPoolGroup> 泛型集合。
所謂的鏈接池,就是一個與鏈接對象Connection 相關的集合,這不僅是簡單的集合,而是有必定的機制在內部。咱們作開發時,可能創建Connection 鏈接對象,關閉鏈接對象,有時候還調用Dispose 來釋放鏈接。下次再用時,便從新實例化一個鏈接。但在池中的鏈接不隨鏈接對象的Close Dispose 而釋放。若是下次從新創建鏈接,鏈接字符串與前一次徹底如出一轍,則鏈接池就會把上次可用的鏈接對象賦給鏈接去用。若是兩個鏈接字符串有一點不同,即便在某一個地方多一個空格,鏈接池也不會覺得是相同的鏈接,這點微軟可能在內部只直接去比較兩個字符串了,而不是比較鏈接數據庫字符串的鍵值互相匹配。
鏈接池的好處就是保留鏈接對象,防止下次重頭再來實例化一個鏈接對象。
 
說明:可能找到結果後以爲很是簡單,但怎麼找到結果的,倒是費了很大勁,幾乎是5 個小時,因此相把找到結果的過程簡單說一下:
一開始用Reflector 發現SqlConnection 中有一個PoolGroup 的屬性,因而就想在運行時候比較兩個SqlConnection 對象的這個屬性,但因爲這個屬性是的訪問修飾符是internal 的,不能直接訪問,只有用反射,代碼(是通過優化的)以下:
            string constr1 = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;";
            string constr2 = "Data Source=(local);Initial Catalog=Pubs;Integrated Security=SSPI;";
            string AssMark = "System.Data,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
            Assembly ass = Assembly.Load(AssMark);
 
            Type SqlConType = null;
            foreach (Type conType in ass.GetExportedTypes())
            {
                Console.WriteLine(conType .ToString ());
                if ("System.Data.SqlClient.SqlConnection" == conType.ToString())
                {
                    SqlConType = conType;
                }
            }
            if (SqlConType != null)
            {
                Type[] types1 = new Type[0];
                ConstructorInfo constructorInfoObj1 = SqlConType.GetConstructor(
                     BindingFlags.Instance | BindingFlags.Public, null,
                     CallingConventions.HasThis, types1, null);
                SqlConnection con1 = (SqlConnection)constructorInfoObj1.Invoke(null);
                con1.ConnectionString = constr1;           
                SqlConnection con2 = (SqlConnection)constructorInfoObj1.Invoke(null);
                con2.ConnectionString = constr2;
                PropertyInfo PI = SqlConType.GetProperty("PoolGroup", BindingFlags.Instance | BindingFlags.NonPublic);
                object poolGroup1 = PI.GetValue(con1, null);
                object poolGroup2 = PI.GetValue(con2, null); 
            }
而後在倒數第一行設置斷點,爲比較poolGroup1 poolGroup2 的不一樣,結果發現,當鏈接字符串同樣時,這兩個對象的_objectID 相同,字符串有一點不一樣就會不一樣,這點說明鏈接池中是用字符串自己比較的,而不是字符串中鍵值對進行比較。同還發現當con1 con2 ConnectionString 不賦值時這兩個對象都是null ,由此說明關鍵是ConnectionString 賦值上,因此纔開始用Reflector 查看這個屬性的賦值方法,纔有上面的代碼。)

0html

收藏微信

桂素偉

199篇文章,105W+人氣,42粉絲

相關文章
相關標籤/搜索