ADO.Net入门(2)

(转载)

作者:可米小子 
出处:http://liuhaorain.cnblogs.com

1. 什么是连接池?

在上篇文章《你必须知道的ADO.NET(四) 品味Connection对象》中,我已经强调过,建立一个数据库连接是一件非常耗时(消耗时间)耗力(消耗资源)的事情。之所以会这样,是因为连接到数据库服务器需要经历几个漫长的过程:建立物理通道(例如套接字或命名管道),与服务器进行初次握手,分析连接字符串信息,由服务器对连接进行身份验证,运行检查以便在当前事务中登记等等。我们先不管为什么会有这样的机制,存在总是有它的道理。既然新建一条连接如此痛苦,那么为什么不重复利用已有的连接呢?

实际上,ADO.NET已经为我们提供了名为连接池的优化方法。连接池就是这样一个容器:它存放了一定数量的与数据库服务器的物理连接。因此,当我们需要连接数据库服务器的时候,只需去池(容器)中取出一条空闲的连接,而不是新建一条连接。这样的话,我们就可以大大减少连接数据库的开销,从而提高了应用程序的性能。

 PS:本来做了2张图片来描述连接池的,无奈公司装有监控软件,不能上传,所以只能等下次有时间上传了。

2. 连接池的工作原理

2.1 创建连接池

需要说明的是,连接池是具有类别区分的。也就是说,同一个时刻同一应用程序域可以有多个不同类型的连接池。那么,连接池是如何标识区分的?细致的讲,是由进程、应用程序域、连接字符串以及windows标识(在使用集成的安全性时)共同组成签名来标识区分的。但对于同一应用程序域来说,一般只由连接字符串来标识区分。当打开一条连接时,如果该条连接的类型签名与现有的连接池类型不匹配,则创建一个新的连接池。反之,则不创建新的连接池。

一个典型的创建连接的实例:

//创建连接对象1using (SqlConnection conn1 =

             new SqlConnection(  "DataSource=(local);Integrated Security=SSPI;Initial Catalog=Northwind"))    {            conn1.Open();       }

//创建连接对象2using (SqlConnection conn2 =

           new SqlConnection(  "DataSource=(local);Integrated Security=SSPI;Initial Catalog=pubs"))   {           conn2.Open();      }

//创建连接对象3using (SqlConnection conn3 =

         new SqlConnection(  "DataSource=(local);Integrated Security=SSPI;Initial Catalog=Northwind"))  {            conn3.Open();      } 

上面实例中,我创建了三个SqlConnection对象,但是管理时只需要两个连接池。细心的朋友,可能早已发现conn1与conn3的连接字符串相同,所以可以共享一个连接池,而conn2与conn1与conn3不同,所以需要创建新的连接池。

2.2 分配空闲连接

当用户创建连接请求或者说调用Connection对象的Open时,连接池管理器首先需要根据连接请求的类型签名找到匹配类型的连接池,然后尽力分配一条空闲连接。具体情况如下:

  • 如果池中有空闲连接可用,返回该连接。
  • 如果池中连接都已用完,创建一个新连接添加到池中。
  • 如果池中连接已达到最大连接数,请求进入等待队列直到有空闲连接可用。

2.3 移除无效连接

无效连接,即不能正确连接到数据库服务器的连接。对于连接池来说,存储的与数据库服务器的连接的数量是有限的。因此,对于无效连接,如果如不及时移除,将会浪费连接池的空间。其实你不用担心,连接池管理器已经很好的为我们处理了这些问题。如果连接长时间空闲,或检测到与服务器的连接已断开,连接池管理器会将该连接从池中移除。

2.4 回收使用完的连接

 当我们使用完一条连接时,应当及时关闭或释放连接,以便连接可以返回池中重复利用。我们可以通过Connection对象的Close或Dispose方法,也可以通过C#的using语句来关闭连接。

3. 说说几个非常重要属性

连接池的行为可以通过连接字符串来控制,主要包括四个重要的属性:

  • Connection Timeout:连接请求等待超时时间。默认为15秒,单位为秒。
  • Max Pool Size: 连接池中最大连接数。默认为100。
  • Min Pool Size: 连接池中最小连接数。默认为0。
  • Pooling: 是否启用连接池。ADO.NET默认是启用连接池的,因此,你需要手动设置Pooling=false来禁用连接池。

还是看一个实例来理解连接池的属性吧。代码如下:

SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();            connStr.DataSource = @".\SQLEXPRESS";            connStr.InitialCatalog = "master";            connStr.IntegratedSecurity = true;

            connStr.Pooling = true; //开启连接池         connStr.MinPoolSize = 0; //设置最小连接数为0            connStr.MaxPoolSize = 50; //设置最大连接数为50                         connStr.ConnectTimeout = 10; //设置超时时间为10秒

            using( SqlConnection conn = new SqlConnection(connStr.ConnectionString))            {                ;//todo            }

4. 连接池异常与处理方法

当用户打开一个连接而没有正确或者及时的关闭时,经常会引发“连接泄露”问题。泄露的连接,会一直保持打开状态,直到调用Dispose方法,垃圾回收器(GC)才关闭和释放连接。与ADO不同,ADO.NET需要手动的关闭使用完的连接。一个重要的误区是:当连接对象超出局部作用域范围时,就会关闭连接。实际上,当超出作用域时,释放的只是连接对象而非连接资源。好吧,还是先看看一个实例吧。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;using System.Data.SqlClient;

namespace ConnectionPool{    class Program    {        static void Main(string[] args)        {            SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();            connStr.DataSource = @".\SQLEXPRESS";            connStr.InitialCatalog = "master";            connStr.IntegratedSecurity = true;

            connStr.MaxPoolSize = 5;//设置最大连接池为5            connStr.ConnectTimeout = 1;//设置超时时间为1秒

              SqlConnection conn = null;            for (int i = 1; i <= 100; ++i)            {                conn = new SqlConnection(connStr.ConnectionString);                try                {                    conn.Open();                    Console.WriteLine("Connection{0} is linked",i);                }                catch(Exception ex)                {                    Console.WriteLine("\n异常信息:\n{0}",ex.Message);                    break;                }            }

            Console.Read();

        }    }}

为了使结果更明显,我特地将最大连接数设置为5,超时时间为1秒。运行后,很快得到以下结果。

从上面的结果我们很明显的知道,连接出现了异常。我们已经知道连接池的最大连接数为5,当创建第6条连接时,由于连接池中连接数量已经达到了最大数并且没有空闲的连接,因此需要等待连接直到超时。当超过超时时间时,就出现了上述的连接异常。因此,我必须再次强调,使用完的连接应当尽快的正确的关闭和释放。

5. 监视SQL Server连接状态的方法

(1)通过活动监视器

第一步:打开MSSMS管理器,单击“活动监视器”图标。

第二步:在打开活动监视器视图中,单击“进程”选项卡。

第三步:运行 #4 连接池异常与处理方法 中的例子,则可以看到打开的5条连接,如下图所示。

(2)使用T-SQL语句

同样,通过执行系统存储过程sp_who,我们也可以监视连接状态。

exec sp_who

可得到以下结果:

6. 高效使用连接池的基本原则

用好连接池将会大大提高应用程序的性能。相反,如果使用不当的话,则百害而无一益。一般来说,应当遵循以下原则:

  • 在最晚的时刻申请连接,在最早的时候释放连接。
  • 关闭连接时先关闭相关用户定义的事务。
  • 确保并维持连接池中至少有一个打开的连接。
  • 尽力避免池碎片的产生。主要包括集成安全性产生的池碎片以及使用许多数据库产生的池碎片。

提示:池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会创建大量在进程退出后才会释放的池。 这样,将打开大量的连接,占用许多内存,从而导致性能降低。

时间: 2024-10-06 17:10:33

ADO.Net入门(2)的相关文章

ADO.NET入门教程(二)了解.NET数据提供程序

摘要 在上一篇文章<你必须知道的ADO.NET(一) 初识ADO.NET>中,我们知道ADO.NET的两大核心组件分别是Data Provider和DataSet.如果说DataSet是ADO.NET的心脏,那么Data Provider绝对是ADO.NET的左臂右膀.Data Provider提供了访问外部数据数据源的可能性,而且外部的数据源是多样的.本文将详细说明.NET数据提供程序的作用以及如何访问不同的数据源. 目录 什么是.NET数据提供程序? .NET数据提供程序的核心对象 其他重

ADO.NET入门教程(三) 连接字符串,你小觑了吗?

摘要 ADO.NET强大的优势在于对不同的数据源提供一致的访问.在上一篇文章<你必须知道的ADO.NET(二)了解.NET数据提供程序>中,我们知道.NET对不同数据源,使用不同的数据提供程序,这使得我们可以更高效的访问相应的数据源.除了.NET数据提供程序外,我还得说说另外一位功臣:连接字符串(Connection Strings),它也为ADO.NET在解决"不同"与"一致"的矛盾中,贡献出了非常重要的力量. 目录 什么是连接字符串? 理解语法格式

ADO.NET入门教程(五) 细说数据库连接池

题外话 通过前几章的学习,不知道大家对ADO.NET有一定的了解了没有.撇开文章质量不讲,必须肯定的是,我是用心去写每一篇文章的.无论是是在排版上,还是在内容选取上我都花了不少心思.我希望通过本系列文章,无论是新手还是老手,在ADO.NET上都能有所收获.如果大家觉得有帮助,我希望能得到您的推荐和关注,让我知道您对我的肯定.如果大家觉得我写的不好,我也很乐意听取批评的意见,让我们一起进步. 摘要 今天我要讲的是数据库连接池.说实话,我表示鸭梨很大.因为相比其他章节来说,连接池相对来说难理解一点.

ADO.NET入门教程(一) 初识ADO.NET

摘要 作为.NET框架最重要的组件之一,ADO.NET扮演着应用程序与数据交互的重要的角色.本文将从宏观的角度来探讨ADO.NET,和大家一起了解ADO.NET来龙去脉以及ADO.NET的主要组成部分. 目录 什么是ADO.NET? 理清ADO.NET与ADO的关系 认识ADO.NET最核心的组成部分 ADO.NET扩展 1. 什么是ADO.NET? 简单的讲,ADO.NET是一组允许.NET开发人员使用标准的,结构化的,甚至无连接的方式与数据交互的技术.对于ADO.NET来说,可以处理数据源是

ADO.Net入门

本文转载自: 作者:可米小子 出处:http://liuhaorain.cnblogs.com 1. 理解Connection对象 Connection对象,顾名思义,表示与特定数据源的连接.如果把数据源比作大门,那么连接字符串则是钥匙,而连接对象则是拿着钥匙开门的人.对于ADO.NET而言,不同的数据源,都对应着不同的Connection对象.具体Connection对象如下表: 名称 命名空间 描述 SqlConnection System.Data.SqlClient 表示与SQL Ser

ADO.NET入门教程(七) 谈谈Command对象高级应用

摘要 在上一篇文章<你必须知道的ADO.NET(六) 谈谈Command对象与数据检索>中,我详细讲解了Command对象的基础知识以及基本用法.作为ADO.NET中最具执行力的对象,Command对象实属变幻莫测.在本文中,我将与大家一起探讨Command对象的高级应用与技巧. 目录 异步执行命令 请使用参数化查询 获取插入行的ID 总结 1. 异步执行命令 在ADO.NET 2.0版本之前,执行Command对象命令时,需要等待命令完成才能执行其他操作.比如,执行ExcuteNonQuer

ADO.NET入门教程(四) 品味Connection对象

摘要 前几篇文章,我都没有详细讲解Data Provider核心对象,因为我希望在讲解这些对象之前,让大家对一些基础的概念有很好的认识.在上一篇文章<你必须知道的ADO.NET(三) 连接字符串,你小觑了吗>中,我详细讲解了连接字符串,相信大家都和我一样意识到它的重要性了.如果说连接字符串是打开数据源大门的钥匙,那么我今天要讲解的则是如何用这把钥匙打开数据源的大门.作为Data Provider的第一核心对象,Connection对象肩负起连接数据源的重任.下面就让我们好好认识这位重量级人物吧

ADO.NET入门教程(八) 深入理解DataAdapter(上)

摘要 ADO.NET有两个核心组件:基于连接的Data Provider组件以及基于非连接的DataSet组件.基于连接的Data Provider组件常用于实时地从数据库中检索数据.而基于非连接的DataSet,似乎与数据库没有直接联系,仅仅用于在本地内存中存储Data Provider提供的数据表或集合.这一切似乎很微妙,此时,你是否在想:这两大组件是如何联系在一起的呢?或许,通过阅读本文会或多或少解除你的一些疑惑呢! 目录 认识DataAdapter DataAdapter的工作原理 说说

ADO.NET入门教程(六) 谈谈Command对象与数据检索

摘要 到目前为止,我相信大家对于ADO.NET如何与外部数据源建立连接以及如何提高连接性能等相关知识已经牢固于心了.连接对象作为ADO.NET的主力先锋,为用户与数据库交互搭建了扎实的桥梁.它的一生是平凡而又伟大的,总是尽自己最大的努力为用户搭建一条通往数据库的平坦大道.相比连接对象来说,Command对象似乎耀眼的多.Command对象在ADO.NET世界里总是忙忙碌碌,它就像一个外交官,为用户传达了所有操作数据库的信息. 目录 准备 什么是Command对象? 必须掌握的几个属性 必须掌握的