日期:2014-05-16  浏览次数:20350 次

管理数据库连接不得不注意的地方

 

对于Asp.Net应用程序,当面对大量用户的请求,我们的服务器是否有能力从容应对,一方面取决于我们服务器硬件设备的处理能力,更重要的一方面则取决于数据库连接的管理是否合理。(这里代码是否合理,暂不考虑,假定它合理。)

 

本文主要讨论数据库连接的管理,即连接池的管理需要注意的问题,并通过代码实例进行分析。

 

注意一:

连接池中包含打开的可重用的数据库连接。在同一时刻同一应用程序域中可以有多个连接池。

一个连接池是通过一个唯一的连接字符串来创建。连接池是根据第一次请求数据库连接的连接字符串来创建的,当另外一个不同的连接字符串请求数据库连接时,将创建另一个连接池。因此一个连接字符中对应一个连接池而不是一个数据库对应一个连接池

 

//代码1

  private string strCon = "Data Source=192.168.24.251;Initial Catalog=Test;Persist Security Info=True;User id=sa;Password=123456;";

     SqlConnection sqlCon = new SqlConnection(strCon);

     sqlCon.Open();

//代码2

 private string strCon = "Data Source=192.168.24.251;Initial Catalog=Test;Persist Security Info=True;User id=“user1”;Password=123456;";

     SqlConnection sqlCon = new SqlConnection(strCon);

     sqlCon.Open();

//代码3

 private string strCon = "Data Source=192.168.24.251;Initial Catalog=Test;Persist Security Info=True;User id=sa;Password=123456;";

     SqlConnection sqlCon = new SqlConnection(strCon);

     sqlCon.Open();

 

 

如果分别运行上述三段代码,会建立几个连接池?答案是2个,代码1新建连接池,代码3与代码1的连接字符串一样,不再新建,与代码1共享一个连接池。代码2与代码1,代码3的连接字符串不一样,则会新建一个连接池

 

所以,为了保证某些连接对象属于一个连接池,连接字符串不能有任何变化,包括大小写,包括空格,都不能有任何变化。  

 

注意二:

ADO.Net默认打开了连接池,不需要再进行手工配置,但也要有相应的连接字符串配合,才能真正提高程序效率。下面谈一下最重要的几个参数。

 

看下面这个连接字符串

"Data Source=192.168.24.251;Initial Catalog=BasicDataSystem;Persist Security Info=True;User id=sa;Password=123456;pooling=true;max pool size=1000;min pool size=200;"

 

连接池的工作原理可以用三句话简单概括:1、如果有未用连接可用,返回该连接;2、如果池中连接都已用完,创建一个新连接添加到池中;3、如果池中连接已达到最大连接数,请求进入等待队列直到有空闲连接可用

了解了基本原理我们很容易理解这些参数:

       pooling 表示是否打开连接池,默认为打开,关掉时需要 pooling = false;

    min pool size 表示连接池最少保存几个连接对象,连接池新建的时候,自动创建的空闲连接;默认为0

    max pool size 表示连接池最多保存几个连接对象,最大值不能超过32767,也不能小于最小值或者0。默认为100

 

还有一个Connect Timeout参数,当连接被返回到池时,将其创建时间与当前时间作比较,如果时间长度(以秒为单位)超出了由 Connection Lifetime 指定的值,该连接就会被销毁。Connection Lifetime是用于集群数据库环境下很有用,用于强制执行运行中的服务器和刚置于联机状态的服务器之间的负载平衡。小规模系统并不常用。

 

怎么理解?

例如一个应用系统的中间层访问一个由3台服务器组成的集群数据库,该系统运行一段时间后发现数据库的负荷太大而需要增加第4台数据库服务器。如果不设置Connection Lifetime,你可能会发现新增加的服务器很久都得不到连接而原来3台服务器的负荷一点都没减少。这是因为中间层的连接一直都不会销毁而建立新的连接的可能性很小(除非出现增加服务器之后数据库的并发访问量超过增加前的并发最大值)。

    注意:Connection Lifetime很容易让人产生误解。不要认为Connection Lifetime决定了一个连接的生存时间。因为只有连接被释放回连接池的时刻(Close连接之后)才会检查Connection Lifetime值是否达到而决定是否销毁连接,而连接在空闲或者正在使用的时候并不会检查Connection Lifetime。这意味着绝大多数情况下连接从建立到销毁经过的时间比Connection Lifetime大。另外,如果Min Pool Size为N (N > 0),那么连接池里有N个连接不受Connection Lifetime影响。这N个连接会一直在池里直到连接池被销毁。

    (2)当发现某个连接对应的“物理连接”断开(这种连接称为“死连接”),例如数据库已经被shutdown、网络中断、SQL Server的连接进程被kill、Oracle的连接会话被kill,该连接被销毁。“死连接”出现后不是立刻被发现,直到该连接被占用来访问数据库的时候才会被发现。

    注意:如果执行Open()方法时候Data Provider只需从连接池取出已有的连接,那么Open()并没有访问数据库,所以这时候“死连接”还不能被发现。

 

注意三:在利用连接池功能时,调用SqlConnection.close()方法关闭连接。如果不显式地关闭连接,当前正使用的连接就不会被放入到连接池中,虽然最终Ado.net会回收这些未关闭的连接,不过那可能需要很长的时间,并且无法确定连接到底会在什么时候回收。

 

代码4:

//常规做法

    SqlConnection con = new SqlConnection(strConn);

    try

    {

       con.Open();

       //进行各种数据库操作

    }

    catch(Excepti