数据库连接及线程池技术原理解析_第1页
数据库连接及线程池技术原理解析_第2页
数据库连接及线程池技术原理解析_第3页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、数据库连接及线程池曾几何时,记住了一句话: “建立数据库连接是一个代价高昂的过程 ”,也从那 时开始,我在构建系统时,一旦建立起了数据库连接,就保存起来,任何要用数 据库的地方,都使用这个数据库连接对象进行操作。这样的行为,在以前写的单线程程序中,倒也可以接受,但在这次写的多线 程程序中,就出现问题了。在这次的程序中,最开始设计时,在工作线程类中, 设置了一个 SqlConnection 的静态成员以接受系统中已经建立起的数据库连接对 象。大致的代码如下:public class NoPoolThread= null;= null;private bool Continue = false;p

2、ublic void Start(if (WorkThread = nullThreadStart workfun = new ThreadStart(DoWork;WorkThread = new Thread(workfun;Continue = true;WorkThread.Start(;!=private void DoWork( null;while (Continue/ 省略了使用数据库连接对象进行操作的代码Thread.Sleep(300;/ end whilepublic void Stop(if (WorkThread != nullContinue = false;在主程

3、序中,使用下面的代码来启动工作线程SqlConnection connection = null;NoPoolThread threads = new NoPoolThread99;private void button1_Click(object sender, EventArgs econnection = new SqlConnection(GetConnectString(;connection.Open(;NoPoolThread.DatabaseConnection = connection;for ( int i=0; ithreadsi = new NoPoolThread(;

4、threadsi.Start(;凭借以往的经验,满心期望着: NoPoolThread 你给我好好干吧,成功就在 眼前。殊不知,异常马上就出现,基本上是说: “已有打开的与此命令相关联 的 DataReader ,必须首先将它关闭。 ExecuteNonQuery 要求已打开且可用的连 接。连接的当前状态为已关闭 ”。然后把 threads 数组长度改成 1,即又恢复到只有一个线程使用数据库 连接对象时,就又恢复正常。这样就说明了,在多个线程中使用同一个 SqlConnection 对象进行数据 库操作的想法是不现实的也是行不通的。于是,就大着胆子,冒着 “巨大的代价 ”,进行修改,在任何使用

5、 SqlConnection 的地方,都临时创建的 SqlConnection 对象一个对象,但是要 创建对象,需要连接字符串啊,怎么来呢,不想重新写一遍,就用现成 的、已经传到线程对象里面的哪个数据库连接对象里面的连接字符串 吧,于是修改代码如下:private void DoWork(!= null;newSqlConnection connection = SqlConnection(DatabaseConnection.ConnectionString;while (Continue/使用 connection 对象Thread.Sleep(300;/ end whileconnect

6、ion.Close(;3.2 SqlConnection 的连接这样修改的结果,每个线程使用自己的 SqlConnection 对象对数据库进 行操作,使各个线程之间互不影响。根据测试,程序可以顺畅运行,而 且在性能上没有明显损失,这多少有些以为,于是继续查找资料。由于 使用的时 SqlConnection 对象,所以就以它为线索,首先从 MSDN 开始, MSDN 给出的解释有如下内容:SqlConnection 对象表示与 SQL Server 数据源的一个唯一的会话。 对于客户端 /服务器数据库系统,它等效于到服务器的网络连接。 SqlConnection 与 SqlDataAdapte

7、r 和 SqlCommand 一 起 使 用 , 可 以 在 连 接 Microsoft SQL Server 数据库时提高性能。对于所有第三方 SQL 服务 器产品以及其他支持 OLE DB 的数据源,请使用 OleDbConnection。当创建 SqlConnection 的实例时,所有属性都设置为它们的初始 值。有关这些值的列表,请参见 SqlConnection 构造函数。如果 SqlConnection 超出范围,则不会将其关闭。因此,必须通过 调用 Close 或 Dispose 显式关闭该连接。它们在功能上是等效的。如果 将连接池值 Pooling 设置为 true 或 yes

8、,则也会释放物理连接。还可以 打开 using 块内部的连接,以确保当代码退出 using 块时关闭该连接。注意:若要部署高性能应用程序,则必须使用连接池。在使用用 于 SQL Server 的 .NET Framework 数据提供程序时,不必启用连接池, 因为提供程序会自动对此进行管理,不过您可以修改某些设置。从上面的解释来看,我修改后的代码,无意间启用了数据库连接池 因为除非你在连接字符串里面明确禁用连接池功能,否则默认的数据 库连接是从连接池中获得连接的。3.3 连接池的相关概念这里,既然提及了连接池,自己在这方面的认识又很模糊,于是就自 己给自己了一个学习连接池的机会。连接池及 AD

9、O.NET连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道 (例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信 息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等 等。 这就是建立数据库连接的代价,但仍然只是定性的描述 。实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味 着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使 打开的连接成本最低, ADO.NET 使用称为 连接池 的优化方法。连接池是一种在打开数据存储区的连接时提高应用程序性能的机制, 可以显著提高应用程序的性能和可缩放性。使用连接池减少新连接

10、需要 打开的次数。池进程 保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来 管理连接。只要用户在连接上调用 Open,池进程就会检查池中是否有可用的连 接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程 序在该连接上调用 Close 时,池进程会将连接返回到活动连接池集中,而不是真正 关闭连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。只有配置相同的连接可以建立池连接 。ADO.NET 同时保留多个池,每个配置一个 池。连接由连接字符串以及 Windows 标识(在使用集成的安全性时)分为多个 池。池连接可以大大提高应用程序的性能和可缩放

11、性,考虑一个访问 SQL Server 数据 库的典型 ASP.NET 或 WebServices 应用程序。客户端应用程序每次需要查询数据 库时,就会在服务器端代码中进行往返,以打开 SqlConnection 来执行查询。在许 多此类应用程序中,这一代码以相同凭据一次又一次地连接到相同数据库。理论 上,这意味着客户端应用程序每次需要执行查询时,服务器端代码需要执行三个操 作 登录到数据库 ( 需要检查所提供的凭据、执行查询、然后注销。连接池可以 真正地提高此类应用程序的性能 通过将内部连接存储在池中,并在以后进行重 复利用,就不再因为登录数据库以及从中注销而降低性能。对 SqlConnec

12、tion 对象 的 Open 和 Close 方法的调用可以短时间内返回,从而可以提高代码的性能和响应 速度 (请参见 3.1 图。图 3.1 典型 ASP.NET 或 WebServices 应用程序中的连接池默认情况下, ADO.NET 中启用连接池。除非显式禁用,否则,连接在应用程序中 打开和关闭时,池进程将对连接进行优化。还可以提供几个连接字符串修饰符来控 制连接池的行为。有关更多信息,请参见 MSDN 中的 “使用连接字符串关键字控制 连接池 ”。在调用 SqlConnection对象的 Close方法时, SQL Client .NET 数据提供程序并不实 际关闭内部连接。相反,数

13、据提供程序将该内部连接存储到一个池中,以便在以后 再次使用。甚至在 SqlConnection 对象被处理之后,该内部连接也保留在池中。如 果在以后使用相同连接字符串和凭据调用 SqlConnection 对象的 Open 方法,将会 再次使用同一内部连接与数据库进行通信。因此,微软建议在使用完连接时一定要关闭或断开连接,以便连接可以 返回池。要关闭连接,可以使用 Connection 对象的 Close 或 Dispose 方法, 也可以通过在 C# 的 using 语句中或在 Visual Basic 的 Using 语句中打开所有 连接。不是显式关闭的连接可能不会添加或返回到池中。例如,

14、如果连 接已超出范围但没有显式关闭,则仅当达到最大池大小而该连接仍然有 效时,该连接才会返回到连接池中。不是显式关闭的连接可能无法返回 池。例如,如果连接已超出范围但没有显式关闭,则仅当达到最大池大 小而该连接仍然有效时,该连接才会返回到连接池中。参见下面的示 例。另外,如果你希望确认是否真正再次利用了同一内部连接,可以使用.NET Reflection 中的功能以可编程方式访问私有 InnerConnection 属性的内 容。以下代码 (其需要对 System.Reflection命名空间的引用在 Using 代码块中 打开一个 SqlConnection,并存储 SqlConnectio

15、n 的 InnerConnection属性的值。 通过利用 Using 代码块,在该代码块的末尾隐式处理了SqlConnection。此代码在 Using 代码块中打开另一个 SqlConnection,并存储 SqlConnection 的 InnerConnection 属性的值。最后,此代码对比 InnerConnection 属性的内容, 确认它们实际上为同一对象。string strConn = "Data Source=.SQLExpress;Integrated Security=True;" PropertyInfo propInnerConn;propIn

16、nerConn = typeof(SqlConnection.GetProperty("InnerConnection", BindingFlags.NonPublic | BindingFlags.Instance;object objInnerConn1, objInnerConn2;using (SqlConnection cn = new SqlConnection(strConn cn.Open(;objInnerConn1 = propInnerConn.GetValue(cn, null;cn.Close(;using (SqlConnection cn =

17、new SqlConnection(strConncn.Open(;objInnerConn2 = propInnerConn.GetValue(cn, null;cn.Close(;Console.WriteLine(objInnerConn1 = objInnerConn2;两个 SqlConnection 对象是在不同的 Using 代码块中创建的,所以其资 源将在每个 Using 代码块的末尾被清除。 InnerConnection 属性的内容及其 所封装的物理连接没有被处理,而是存储在池中,以便在以后被再次利 用。注意 如果在连接字符串中禁用了连接池 (稍后将解释如何禁用,将 会看到

18、此内部连接不能被重复利用。连接池的创建和清除在初次打数据库开连接时 例如调用 SqlConnection.Open方法时, 池 进程将根据完全匹配算法创建连接池,该算法将池与连接中的连接字符串 关联。每个连接池与不同的连接字符串关联。打开新连接时,如果连接 字符串并非与现有池完全匹配,将创建一个新池。按进程、按应用程序 域、按连接字符串以及(在使用集成的安全性时)按 Windows 标识来建立 池连接。ADO.NET 2.0 引 入 了 两 种 新 的 方 法 来 清 除 池 : ClearAllPools 和 ClearPool。 ClearAllPools 清 除 给 定 提 供 程 序

19、的 连 接 池 , ClearPool 清除与特定连接关联的连接池。如果在调用时连接正在使用,将 进行相应的标记。连接关闭时,将被丢弃,而不是返回池中。连接的添加和移除连接池是为每个唯一的连接字符串创建的。当创建一个池后,将创建多个连接 对象并将其添加到该池中,以满足最小池大小的要求。连接根据需要添加到池中, 但是不能超过指定的最大池大小(默认值为 100)。连接在关闭或断开时释放回池 中。在请求 SqlConnection 对象时,如果存在可用的连接,将从池中获取该对象。连接 要可用,必须未使用,具有匹配的事务上下文或未与任何事务上下文关联,并且具 有与服务器的有效链接。连接池进程通过在连接

20、释放回池中时重新分配连接,来满足这些连接请求。如 果已达到最大池大小且不存在可用的连接,则该请求将会排队。然后,池进程尝试 重新建立任何连接,直到到达超时时间(默认值为 15 秒)。如果池进程在连接超 时之前无法满足请求,将引发异常。连接池进程定期扫描连接池,查找没有通过Close 或 Dispose 关闭的未用连接,并重新建立找到的连接。如果应用程序没有显式关闭或断开其连接,连接池进 程可能需要很长时间才能重新建立连接,所 以,最好确保在连接 中显式调 用 Close 和 Dispose。如果连接长时间空闲,或池进程检测到与服务器的连接已断开,连接池进程会 将该连接从池中移除。注意,只有在尝

21、试与服务器进行通信之后才能检测到断开的 连接。如果发现某连接不再连接到服务器,则会将其标记为无效。无效连接只有在 关闭或重新建立后,才会从连接池中移除。如果存在与已消失的服务器的连接,那么即使连接池管理程序未检测到已断开 的连接并将其标记为无效,仍有可能将此连接从池中取出。这种情况是因为检查连 接是否仍有效的系统开销将造成与服务器的另一次往返,从而抵消了池进程的优 势。发生此情况时,初次尝试使用该连接将检测连接是否曾断开,并引发异常。上述连接的添加和移除,全都是由后台运行的池进程管理的。禁用连接池您可能不希望使用连接池。例如,如果正在使用一个直接与数据库进行通信的 简单 Windows 应用程

22、序,那么可能希望禁用连接池。在采用这一架构时,各个客 户端应用程序需要自己的连接。在启用连接池时,每个应用程序的连接被放入池 中,如果在清除连接池之前重新打开该连接,将重复利用放入池中的连接。所以, 如果应用程序频繁重复使用连接,那么在启用连接池的情况下,对 SqlConnection.Open 的调用将会更快速地返回。但是,这种方法将会导致在任意给 定时刻存在许多活动的数据库连接。禁用连接池将会降低任意时刻的活动数据库连 接数目,但这样会强制所有对 SqlConnection.Open的调用都建立一个新的数据库连 接。如果希望禁用连接池,可以通过向连接字符串中添加 Pooling=False

23、,逐个连接 地禁用连接池。幸运的是,在 ADO.NET 2.0 中不再需要记忆诸如此类的属性。如 果存在疑问,可以检查 SqlConnectionStringBuilder 类的选项。在这个类中可以找到 一个 Pooling 属性,其取值为 Boolean 类型。默认情况下,此值被设置为 True。将 该值设置为 False将会禁止将该连接放入池中。因此,在调用 SqlConnection对象的 Close方法时,将会关闭与数据库的实际连接。注意 在“偶尔进行连接 ”的 Windows 应用程序中,使用连接池可能很有帮助, 具体取决于应用程序。如果应用程序希望定期重新连接到数据库,则可以发挥连接 池的作用,将与数据库的物理连接保持打开状态,至少暂时如此。如果在从池中删 除该物理连接之前,应用程序尝试重新连接到该数据库,则连接池逻辑 (pooling logic 将会重新使用与该数据库的物理连接。查看数据库连接在使用了数据库连接池的情况下,那么建立到数据库上的连接到

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论