一起谈.NET技术,详解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(" %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 dictionary = this._connectionPoolGroups;

if (!dictionary.TryGetValue(str, out group))

{

Dictionary dictionary2 = new Dictionary(1 + dictionary.Count);

foreach (KeyValuePair 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 dictionary = this._connectionPoolGroups;

if (!dictionary.TryGetValue(str, out group))

{

Dictionary dictionary2 = new Dictionary(1 + dictionary.Count);

foreach (KeyValuePair 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泛型集合。

所谓的连接池,就是一个与连接对象Connection相关的集合,这不只是简单的集合,而是有一定的机制在内部。我们做开发时,可能建立Connection连接对象,关闭连接对象,有时候还调用Dispose来释放连接。下次再用时,便重新实例化一个连接。但在池中的连接不随连接对象的Close或Dispose而释放。如果下次重新建立连接,连接字符串与前一次完全一模一样,则连接池就会把上次可用的连接对象赋给连接去用。如果两个连接字符串有一点不一样,即使在某一个地方多一个空格,连接池也不会以为是相同的连接,这点微软可能在内部只直接去比较两个字符串了,而不是比较连接数据库字符串的键值互相匹配。

连接池的好处就是保留连接对象,防止下次重头再来实例化一个连接对象。


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=b77a5c561
934e089";
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);

}

 

说明:可能找到结果后觉得非常简单,但怎么找到结果的,却是费了很大劲,几乎是5个小时,所以相把找到结果的过程简单说一下:

一开始用Reflector发现SqlConnection中有一个PoolGroup的属性,于是就想在运行时候比较两个SqlConnection对象的这个属性,但由于这个属性是的访问修饰符是internal的,不能直接访问,只有用反射,代码(是经过优化的)如下:

然后在倒数第一行设置断点,为比较poolGroup1和poolGroup2的不同,结果发现,当连接字符串一样时,这两个对象的_objectID相同,字符串有一点不同就会不同,这点说明连接池中是用字符串本身比较的,而不是字符串中键值对进行比较。同还发现当con1和con2的ConnectionString不赋值时这两个对象都是null,由此说明关键是ConnectionString赋值上,所以才开始用Reflector查看这个属性的赋值方法,才有上面的代码。)

时间: 2024-07-29 22:55:51

一起谈.NET技术,详解ADO.NET连接池的相关文章

详解ADO.NET连接池

ADO.NET中提供了连接池的功能,多数开发人员很少设置它,因为它是默认的. 界面设置如下图: 关闭连接池也很简单,在连接字符串如下: Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;Pooling=False; 但连接池的本质是什么样的呢? 用Reflector,打开System.Data.SqlClient.SqlConnection的ConnectionString属性的设置值的方法,如

VPN技术详解(中)

详解 VPN技术详解(中)吕晓波 隧道技术基础 隧道技术是一种通过使用互联网络的基础设施在网络之间传递数据的方式.使用隧道传递的数据(或负载)可以是不同协议的数据桢(此字不正确)或包.隧道协议将这些其它协议的数据桢或包重新封装在新的包头中发送.新的包头提供了路由信息,从而使封装的负载数据能够通过互联网络传递. 被封装的数据包在隧道的两个端点之间通过公共互联网络进行路由.被封装的数据包在公共互联网络上传递时所经过的逻辑路径称为隧道.一旦到达网络终点,数据将被解包并转发到最终目的地.注意隧道技术是指

Tomcat与Java Web开发技术详解连载之一

web|详解 本章介绍如何在Tomcat上创建和发布Web应用.这里首先讲解Tomcat的目录结构以及Web应用的目录结构,接着介绍如何将HTML.Servlet.JSP和Tag Library部署到Web应用中,然后介绍把整个Web应用打包并发布的方法,最后介绍如何在Tomcat上配置虚拟主机. 本章侧重于讨论Web应用的结构和发布方法,所以没有对本章的Servlet和JSP的例子进行详细解释,关于Servlet和JSP的技术可以分别参考其它章节的内容. 2.1 Tomcat的目录结构 在To

Tomcat与Java Web开发技术详解连载之二

web|详解 2.2.4 部署HTML文件 在helloapp目录下加入index.htm文件,这个文件仅仅用来显示一串带链接的字符"Welcome to HelloApp", 它链接到login.jsp文件.以下是index.htm文件的代码: <html><head><title>helloapp</title></head><body ><p><font size="7"

Tomcat与Java Web开发技术详解连载之三

web|详解 2.2.8 创建并发布WAR文件 Tomcat既可以运行采用开放式目录结构的Web应用,也可以运行WAR文件.在本书配套光盘的sourcecode/chapter2/helloapp目录下提供了所有源文件,只要把整个helloapp目录拷贝到/webapps目录下,即可运行开放式目录结构的helloapp应用.在Web应用的开发阶段,为了便于调试,通常采用开放式的目录结构来发布Web应用,这样可以方便地更新或替换文件.如果开发完毕,进入产品发布阶段,应该将整个Web应用打包为WAR

VPN技术详解(上)

详解 VPN技术详解(上)吕晓波 引言 虚拟专用网络可以实现不同网络的组件和资源之间的相互连接.虚拟专用网络能够利用Internet或其它公共互联网络的基础设施为用户创建隧道,并提供与专用网络一样的安全和功能保障.(图1) 虚拟专用网络允许远程通讯方,销售人员或企业分支机构使用Internet等公共互联网络的路由基础设施以安全的方式与位于企业局域网端的企业服务器建立连接.虚拟专用网络对用户端透明,用户好象使用一条专用线路在客户计算机和企业服务器之间建立点对点连接,进行数据的传输. 虚拟专用网络技

VPN技术详解(下)

详解 VPN技术详解(下)吕晓波 (紧接中篇) 数据传输阶段 一旦完成上述4阶段的协商,PPP就开始在连接对等双方之间转发数据.每个被传送的数据报都被封装在PPP包头内,该包头将会在到达接收方之后被去除.如果在阶段1选择使用数据压缩并且在阶段4完成了协商,数据将会在被传送之间进行压缩.类似的,如果如果已经选择使用数据加密并完成了协商,数据(或被压缩数据)将会在传送之前进行加密. 点对点隧道协议(PPTP) PPTP是一个第2层的协议,将PPP数据桢封装在IP数据报内通过IP网络,如Interne

科普:5G网络关键技术详解

不久前,中国华为公司主推的Polar Code(极化码)方案,成为5G控制信道eMBB场景编码方案.消息一出,在网络上就炸开了锅,甚至有媒体用"华为碾压高通,拿下5G时代"来形容这次胜利.那么,媒体报道是否名副其实,除了编码之外,5G还有哪些关键技术呢? 科普:5G网络关键技术详解 5G通信到底是什么 5G,顾名思义是第五代通信技术,3GPP定义了5G三大场景: 增强型移动宽带(eMBB,Enhance Mobile Broadband),按照计划能够在人口密集区为用户提供1Gbps用

Web 缓存欺骗攻击技术详解

本文讲的是Web 缓存欺骗攻击技术详解,Omer Gil早在今年年初就在他的博客上发表了有关于Web缓存欺骗攻击技术的博文,随后他在BlackHat USA 2017 和BSides Tel-Aviv 2017 上对这种攻击技术进行了演示,并做了更深入的研究. 在他发布的"Web 缓存欺骗技术白皮书"中,详细的介绍了这种攻击技术.这份白皮书大致包含了如下内容: ·攻击原理概述 ·实施攻击的方法 ·攻击所需的条件 ·已知的几个主流的Web 框架及缓存机制 ·缓解措施 Web缓存欺骗这种攻