技术开发 频道

ADO.NET数据连接池

【IT168 技术文档】

    3.1增加连接 

    一旦连接池被建立,就立即建立由Min Pool Size指定数量的连接。如果只有一个连接被占用,那么其他的连接(如果Min Pool Size大于1)为池里“可用的”连接。如果某进程有连接请求而且请求的连接的连接串与该进程的某个连接池的连接串相同(如果进程里的所有连接池的连接串都不匹配被请求的连接就需要建立新的连接池),那么如果该连接池里有“可用的”连接就从连接池里取出一个“可用的”的连接使用,如果没有“可用的”连接就建立新的连接。一旦程序运行连接的Close或者Dispose方法后,“被占用的”连接被释放回连接池变为“可用的”连接。需要区分连接池里“连接的数量”与“‘可用的’连接数量”。“连接的数量”指连接池里包括“被占用的”连接与“可用的”连接的数量。 

    如果Max Pool Size已经达到而且所有连接都被占用,新的连接请求需要等待。如果有被占用的连接释放回连接池,那么请求得到该连接;如果请求等待超过Connection Timeout的时间,程序会抛出InvalidOperationException。 

    3.2减少连接 

    两种情况下连接池里的连接会减少。 

    (1)每当一个连接使用完后释放回连接池,如果当前时间减去该连接建立的时间的值大于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()并没有访问数据库,所以这时候“死连接”还不能被发现。 

    下面以一个例子详细解释一个连接池从建立起到进程结束连接数的变化情况。


string connectionString = "server = .;database = northwind;user = sa;
password = sqlserver;min pool size = 2;max pool size = 5;
connection lifetime
= 20;connection timeout = 10";
SqlConnection[] connections = new SqlConnection[7];
for(int i = 0;i < connections.Length;i++) connections[i] = new SqlConnection(connectionString); Open connection[0],8秒后Open connection[1] …8秒后Close connection[0],10秒后Open connection[0] …5秒后Open connection[2][3][4],每隔两秒打开一个 Console.WriteLine("Now the Max Pool Size is reached and
we try
to open connection[5].\r\n"); for(int i = 0;i < 2;i++) { try {connections[5].Open();} catch(InvalidOperationException e) { if(i == 1) return; Console.WriteLine("Can't open connection[5].\r\n" + e.Message); connections[4].Close(); Console.WriteLine("\r\nTry to open connection[5] again."); continue; } } Console.WriteLine("connection[5] is open."); foreach(SqlConnection con in connections) { if(con.State == ConnectionState.Open) { con.Close(); Console.WriteLine("A connection is released back to the pool."); System.Threading.Thread.Sleep(5000); } }

     使用性能监视器观察,得到图4所示结果。我们观察.NET CLR Data的“SqlClient: Current # connection pools”、“SqlClient: Current # pooled connections”以及Sql Server: General Statistic的User Connections计数器。

图4

    由于Min Pool Size = 2,所以open connection[0]的时候连接池里就建立了两个连接。之后open connection[1]、close connection[0]、open connection[0]这段时间里连接池连接数保持为2,因为open连接的并发数量都没超过2。接着,相继open connection[2]、[3]、[4],因为每次请求连接的时候连接池里都没有“可用的”连接,所以每请求一个连接连接数量就增加1,一直攀升到Max Pool Size(5)。这时候connection[0]、[1]的生存时间已经超过Connection Lifetime,但由于它们还没有被Close,所以还会继续生存。接着尝试再请求连接,这时候因为Max Pool Size已达而池里所有连接都被占用,所以第一次尝试失败。进行第二次尝试前先close connection[4],这样就有一个连接被释放回连接池,第二次尝试成功。最后close所有打开的connection,每隔5秒close一个,所有connection被close的时候它们的生存时间都大于Connection Lifetime,但由于Min Pool Size = 2,所以只有3个connection被销毁。 

    另外强调两点: 

    (1)可用看出增加/减少一个连接池的连接,User Connections(即“物理连接”)随着增加/减少一个。(为方便观察,先用Sql Query Analyzer打开一个用户连接) 

    (2)由于使用相同连接串,所以由始至终只有一个连接池。

0
相关文章