一起谈.NET技术,详解ADO.NET连接池

简介: ADO.NET中提供了连接池的功能,多数开发人员很少设置它,因为它是默认的。界面设置如下图: 关闭连接池也很简单,在连接字符串如下:Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;P...

ADO.NET中提供了连接池的功能,多数开发人员很少设置它,因为它是默认的。

界面设置如下图:

 

关闭连接池也很简单,在连接字符串如下:

Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;Pooling=False;

但连接池的本质是什么样的呢?

 

Reflector,打开System.Data.SqlClient.SqlConnectionConnectionString属性的设置值的方法,如下:

 

代码
 
  
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来释放连接。下次再用时,便重新实例化一个连接。但在池中的连接不随连接对象的CloseDispose而释放。如果下次重新建立连接,连接字符串与前一次完全一模一样,则连接池就会把上次可用的连接对象赋给连接去用。如果两个连接字符串有一点不一样,即使在某一个地方多一个空格,连接池也不会以为是相同的连接,这点微软可能在内部只直接去比较两个字符串了,而不是比较连接数据库字符串的键值互相匹配。

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

 
 
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的,不能直接访问,只有用反射,代码(是经过优化的)如下:

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

目录
相关文章
|
2月前
|
人工智能 开发框架 .NET
.NET技术的强大功能:.NET技术的基础特性、在现代开发中的应用、以及它如何助力未来的软件开发。
.NET技术是软件开发领域的核心支柱,以其强大功能、灵活性及安全性广受认可。本文分三部分解析:基础特性如多语言支持、统一运行时环境;现代应用如企业级与Web开发、移动应用、云服务及游戏开发;以及未来趋势如性能优化、容器化、AI集成等,展望.NET在不断变化的技术环境中持续发展与创新。
80 4
|
2月前
|
人工智能 物联网 开发者
.NET技术在现代软件开发中的应用愈发广泛和深入
.NET技术是软件开发的关键支柱,本文分为三部分探讨其创新应用:最新进展如.NET 5/6统一平台、性能提升、跨平台支持增强、云集成优化及开源社区贡献;应用场景涵盖微服务架构、物联网、AI/机器学习、游戏及移动应用开发;未来发展潜力在于持续性能优化、云原生支持、新兴技术集成、生态扩张及教育培训加强。.NET正以其强大适应性和创新潜力引领软件开发的新方向。
37 3
|
17天前
|
人工智能 前端开发 开发工具
解读.NET 技术的开发潜力
本文全面介绍了.NET技术在软件开发领域的核心优势、创新应用及面临的挑战。.NET以其统一的开发平台、强大的工具和跨平台能力,成为企业级应用、Web应用乃至游戏开发的理想选择。然而,在性能优化、容器化及AI集成等方面仍需不断突破。通过积极拥抱开源和社区驱动模式,.NET将持续推动软件开发的进步。
36 1
|
29天前
|
监控 网络协议 API
.NET WebSocket 技术深入解析,你学会了吗?
【9月更文挑战第4天】WebSocket 作为一种全双工协议,凭借低延迟和高性能特点,成为实时应用的首选技术。.NET 框架提供了强大的 WebSocket 支持,使实时通信变得简单。本文介绍 WebSocket 的基本概念、.NET 中的使用方法及编程模型,并探讨其在实时聊天、监控、在线游戏和协同编辑等场景的应用,同时分享最佳实践,帮助开发者构建高效实时应用。
80 12
|
24天前
|
人工智能 前端开发 Devops
.NET技术自发布以来,在软件开发领域发挥了重要作用
【9月更文挑战第12天】.NET技术自发布以来,在软件开发领域发挥了重要作用。本文分为三部分探讨其在现代开发中的应用:首先介绍.NET的核心价值,包括语言多样性、强大的开发工具支持、丰富的类库、跨平台能力和活跃的社区;接着分析其在企业级应用、Web开发、移动应用、云服务及游戏开发中的实际应用;最后讨论.NET面临的挑战与未来趋势,如性能优化、容器化、AI集成及跨平台框架竞争等。通过不断的技术创新和社区驱动,.NET将持续推动软件开发的进步。
28 4
|
28天前
|
人工智能 开发框架 算法
C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)
C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)
|
28天前
|
传感器 应用服务中间件 Linux
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)
|
28天前
|
人工智能 算法 C#
C#/.NET/.NET Core技术前沿周刊 | 第 1 期(2024年8.12-8.18)
C#/.NET/.NET Core技术前沿周刊 | 第 1 期(2024年8.12-8.18)
|
2月前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
29 1
|
2月前
|
Java Spring 自然语言处理
Spring 框架里竟藏着神秘魔法?国际化与本地化的奇妙之旅等你来揭开谜底!
【8月更文挑战第31天】在软件开发中,国际化(I18N)与本地化(L10N)对于满足不同地区用户需求至关重要。Spring框架提供了强大支持,利用资源文件和`MessageSource`实现多语言文本管理。通过配置日期格式和货币符号,进一步完善本地化功能。合理应用这些特性,可显著提升应用的多地区适应性和用户体验。
32 0
下一篇
无影云桌面