在C#中实现连接池

来源:互联网 发布:新奥集团怎么样知乎 编辑:程序博客网 时间:2024/06/07 00:49
SQL使用连接池

连接到数据库服务器通常由几个需要软长时间的步骤组成。必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次连接,必须分析连接字符串信息,必须由服务器对连接进行身份验证,等等。

实际上,大部份的应用程序都是使用一个或几个不同的连接配置。当应用程序的数据量和访问量大的时候,这意味着在运行应用程序的过程中,许多相同的连接将反复地被打开和关闭,从而会引起数据库服务器效率低下甚至引发程序崩溃。为了确保应用程序的稳定和降低性能成本,我们可以在ADO.NET中使用称为连接池的优化方法来管理维护连接。

连接池可以减少创建连接的次数。定义最小连接数(固定连接数),当用户在连接上调用 Open,连接池就会检查池中是否有可用的连接。如果发现有连接可用,会将该连接返回给调用者,而不是创建新连接。应用程序在该连接上调用 Close 时,连接池会判断该连接是否在最小连接数之内,如果“是”会将连接回收到活动连接池中而不是真正关闭连接,否则将烧毁连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。


创建连接池

以下示例使用C# 连接SQL数据库:

  1.  class DbConn
  2.     {
  3.         //using System.Data;
  4.         //using System.Data.SqlClient;
  5.         private const int MaxPool = 10;         //最大连接数
  6.         private const int MinPool = 5;          //最小连接数
  7.         private const bool Asyn_Process = true//设置异步访问数据库
  8.         private const bool Mars = true;         //在单个连接上得到和管理多个、仅向前引用和只读的结果集(ADO.NET2.0) 
  9.         private const int Conn_Timeout = 15;    //设置连接等待时间
  10.         private const int Conn_Lifetime = 15;   //设置连接的生命周期
  11.         private string ConnString = "";         //连接字符串      
  12.         private SqlConnection SqlDrConn = null;  //连接对象
  13.         public DbConn()//构造函数
  14.         {
  15.             ConnString = GetConnString();
  16.             SqlDrConn = new SqlConnection(ConnString);
  17.         }
  18.         private string GetConnString()
  19.         {
  20.             return "server=localhost;"
  21.                 + "integrated security=sspi;"
  22.                 + "database=pubs;"
  23.                 + "Max Pool Size=" + MaxPool + ";"
  24.                 + "Min Pool Size=" + MinPool + ";"
  25.                 + "Connect Timeout=" + Conn_Timeout + ";"
  26.                 + "Connection Lifetime=" + Conn_Lifetime + ";"
  27.                 +"Asynchronous Processing=" + Asyn_Process + ";";
  28.                 //+ "MultipleActiveResultSets=" + Mars + ";";
  29.         }
  30.        
  31.         public DataTable GetDataReader(string StrSql)//数据查询
  32.         {                    
  33.             //当连接处于打开状态时关闭,然后再打开,避免有时候数据不能及时更新
  34.             if (SqlDrConn.State == ConnectionState.Open)
  35.             {
  36.                 SqlDrConn.Close();                
  37.             }
  38.             try
  39.             {
  40.                 SqlDrConn.Open();
  41.                 SqlCommand SqlCmd = new SqlCommand(StrSql, SqlDrConn);
  42.                 SqlDataReader SqlDr = SqlCmd.ExecuteReader();
  43.                 if (SqlDr.HasRows)
  44.                 {
  45.                     DataTable dt = new DataTable();
  46.                     //读取SqlDataReader里的内容
  47.                     dt.Load(SqlDr);
  48.                     //关闭对象和连接
  49.                     SqlDr.Close();
  50.                     SqlDrConn.Close();                    
  51.                     return dt;
  52.                 }
  53.                 return null;
  54.             }
  55.             catch (Exception ex)
  56.             {
  57.                 System.Windows.Forms.MessageBox.Show(ex.Message);          
  58.                 return null;
  59.             }
  60.             finally
  61.             {        
  62.                 SqlDrConn.Close();
  63.             }
  64.         }
  65.     }

通过调用 SqlDrConn.Open()方法打开连接,这时候连接池就会初始化并建立设定的最小连接数。想更清楚了解到连接池的状况可以通过SQL的查询分析器执行存储过程sp_Who,它会列出当前的数据库进程,查看loginname、dbname可以区分用户的连接信息,但要注意的是登录查询分析器本身会使用两个连接,所以最好用另一个用户名登录查询分析器。使用此方法还有一个麻烦地方就是要经常按“执行查询”以更新进程信息。还有另一种方法个人认为较好的,通过 控制面板管理工具性能,右击添加计算器,性能对象选择SQlServer:General Statistics(常规统计)然后计算器选择User Connections(用户连接)最后按“添加”就可以实时查看当前连接数。

到了这里,连接池已经实现了, 但问题往往会出现在运行过程中。如连接池的连接数满了该怎样处理?在这里我们应该合理设置连接字符串中的Connect Timeout属性和Connection Lifetime属性(上面有解释)延长等待时间,尽可能地在每次使用完连接之后调用Close方法关闭连接。但从中也有没法避免的,当连接数满了并且申请连接的时间超过设置连接等待的时间时,程序将会引发InvalidOperationExceptio异常,我们可以通过捕获此异常向用户界面提示“系统正忙,请稍后再连接……”之类的信息来缓解这种情况。此外,也有另一种方法来解决这种情况,就是利用ADO.NET 2.0 新特性“异步进程”,对数据库进行异步操作,确保连接能够及时调用Close方法关闭连接,这样能大大减少正在使用的连接数。

使用方法:在连接字符串中加上Asynchronous Processing=true 表示使用异步处理操作。

当应用程序不再需要用到连接池的时候可以使用ClearPool 或 ClearAllPools方法清空连接池也可作重置连接池使用,方法如下:

         SqlConnection.ClearPool(SqlConnection connection) 清空关联的连接池
         SqlConnection.ClearAllPools() 清空所有连接池

调用上述方法,如果连接正在使用,连接池会做相应标记,等连接关闭时自动烧毁。

0 0