对于ADONET连接池大家不会陌生不过多次用过ADONET连接池的各位NET程序员却不一定深入了解它具体原因是
ADONET中提供了连接池的功能多数开发人员很少设置它因为它是默认的
界面设置如下图
)thisstylewidth=; border=>
关闭连接池也很简单在连接字符串如下
Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;Pooling=False;
但连接池的本质是什么样的呢?
用Reflector打开SystemDataSqlClientSqlConnection的ConnectionString属性的设置值的方法如下
private void ConnectionString_Set(string value)
{
DbConnectionOptions userConnectionOptions = null;
DbConnectionPoolGroup group = thisConnectionFactoryGetConnectionPoolGroup(value null ref userConnectionOptions); DbConnectionInternal innerConnection = thisInnerConnection;
bool allowSetConnectionString = innerConnectionAllowSetConnectionString;
if (allowSetConnectionString)
{
allowSetConnectionString= thisSetInnerConnectionFrom(DbConnectionClosedBusySingletonInstance innerConnection);
if (allowSetConnectionString)
{
this_userConnectionOptions = userConnectionOptions;
this_poolGroup = group;
this_innerConnection = DbConnectionClosedNeverOpenedSingletonInstance;
}
}
if (!allowSetConnectionString)
{
throw ADPOpenConnectionPropertySet(ConnectionString innerConnectionState);
}
if (BidTraceOn)
{
string str = (userConnectionOptions != null) ? userConnectionOptionsUsersConnectionStringForTrace() : ; BidTrace(<provDbConnectionHelperConnectionString_Set|API> %d# %ls\n thisObjectID str);
}
}
再连接 到红色的GetConnectionPoolGroup方法如下代码
internal DbConnectionPoolGroup GetConnectionPoolGroup(string connectionString DbConnectionPoolGroupOptions poolOptions ref DbConnectionOptions userConnectionOptions)
{
DbConnectionPoolGroup group;
if (ADPIsEmpty(connectionString))
{
return null;
}
if (!this_connectionPoolGroupsTryGetValue(connectionString out group) || (groupIsDisabled && (groupPoolGroupOptions != null)))
{
DbConnectionOptions options = thisCreateConnectionOptions(connectionString userConnectionOptions);
if (options == null)
{
throw ADPInternalConnectionError(ADPConnectionErrorConnectionOptionsMissing);
}
string str = connectionString;
if (userConnectionOptions == null)
{
userConnectionOptions = options;
str = optionsExpand();
if (str != connectionString)
{
return thisGetConnectionPoolGroup(str null ref userConnectionOptions);
}
}
if ((poolOptions == null) && ADPIsWindowsNT)
{
if (group != null)
{
poolOptions = groupPoolGroupOptions;
}
else
{
poolOptions = thisCreateConnectionPoolGroupOptions(options);
}
}
DbConnectionPoolGroup group = new DbConnectionPoolGroup(options poolOptions)
{
ProviderInfo = thisCreateConnectionPoolGroupProviderInfo(options)
};
lock (this)
{
Dictionary<string DbConnectionPoolGroup> dictionary = this_connectionPoolGroups;
if (!dictionaryTryGetValue(str out group))
{
Dictionary<string DbConnectionPoolGroup> dictionary = new Dictionary<string DbConnectionPoolGroup>( + dictionaryCount); foreach (KeyValuePair<string DbConnectionPoolGroup> pair in dictionary)
{
dictionaryAdd(pairKey pairValue);
}
dictionaryAdd(str group);
thisPerformanceCountersNumberOfActiveConnectionPoolGroupsIncrement();
group = group;
this_connectionPoolGroups = dictionary;
}
return group;
}
}
if (userConnectionOptions == null)
{
userConnectionOptions = groupConnectionOptions;
} return group; }
TryGetValue是判断是否存在连接字符串为connectionString的连接存在返回到group
不存在就调用CreateConnectionOptions创建一个DbConnectionOptions最后用
lock (this)
{
Dictionary<string DbConnectionPoolGroup> dictionary = this_connectionPoolGroups;
if (!dictionaryTryGetValue(str out group))
{ Dictionary<string DbConnectionPoolGroup> dictionary = new Dictionary<string DbConnectionPoolGroup>( + dictionaryCount); foreach (KeyValuePair<string DbConnectionPoolGroup> pair in dictionary)
{
dictionaryAdd(pairKey pairValue);
}
dictionaryAdd(str group);
thisPerformanceCountersNumberOfActiveConnectionPoolGroupsIncrement();
group = group;
this_connectionPoolGroups = dictionary;
}
return group;
} 这段代码放到连接池中在这里可能显示的看到adoNET的连接池实质上是一个Dictionary<string DbConnectionPoolGroup>泛型集合
所谓的连接池就是一个与连接对象Connection相关的集合这不只是简单的集合而是有一定的机制在内部我们做开发时可能建立Connection连接对象关闭连接对象有时候还调用Dispose来释放连接下次再用时便重新实例化一个连接但在池中的连接不随连接对象的Close或Dispose而释放如果下次重新建立连接连接字符串与前一次完全一模一样则连接池就会把上次可用的连接对象赋给连接去用如果两个连接字符串有一点不一样即使在某一个地方多一个空格连接池也不会以为是相同的连接这点微软可能在内部只直接去比较两个字符串了而不是比较连接数据库字符串的键值互相匹配
连接池的好处就是保留连接对象防止下次重头再来实例化一个连接对象
string constr = Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;;
string constr = Data Source=(local);Initial Catalog=Pubs;Integrated Security=SSPI;;
string AssMark = SystemDataVersion= Culture=neutral PublicKeyToken=bace;
Assembly ass = AssemblyLoad(AssMark);
Type SqlConType = null; foreach (Type conType in assGetExportedTypes())
{
ConsoleWriteLine(conType ToString ());
if (SystemDataSqlClientSqlConnection == conTypeToString())
{
SqlConType = conType;
}
}
if (SqlConType != null)
{
Type[] types = new Type[];
ConstructorInfo constructorInfoObj = SqlConTypeGetConstructor( BindingFlagsInstance | BindingFlagsPublic null CallingConventionsHasThis types null);
SqlConnection con = (SqlConnection)constructorInfoObjInvoke(null);
conConnectionString = constr;
SqlConnection con = (SqlConnection)constructorInfoObjInvoke(null);
conConnectionString = constr;
PropertyInfo PI = SqlConTypeGetProperty(PoolGroup BindingFlagsInstance | BindingFlagsNonPublic);
object poolGroup = PIGetValue(con null);
object poolGroup = PIGetValue(con null); }
(说明可能找到结果后觉得非常简单但怎么找到结果的却是费了很大劲几乎是个小时所以相把找到结果的过程简单说一下
一开始用Reflector发现SqlConnection中有一个PoolGroup的属性于是就想在运行时候比较两个SqlConnection对象的这个属性但由于这个属性是的访问修饰符是internal的不能直接访问只有用反射代码(是经过优化的)如下
然后在倒数第一行设置断点为比较poolGroup和poolGroup的不同结果发现当连接字符串一样时这两个对象的_objectID相同字符串有一点不同就会不同这点说明连接池中是用字符串本身比较的而不是字符串中键值对进行比较同还发现当con和con的ConnectionString不赋值时这两个对象都是null由此说明关键是ConnectionString赋值上所以才开始用Reflector查看这个属性的赋值方法才有上面的代码