为什么要使用连接池?
因为连接数据库是一件非常耗时耗力的一件事。特别影响性能,所以引出了连接池
连接池是什么?
存放了一定数量的与数据库服务器的物理连接的容器。当我们需要使用的时候就从容器中取出一条空闲的连接,而不是创建一个新的连接。
作用:
减少了连接数据库的开销,提高了性能。
分类:
同一时刻,同一应用程序域可以有不同类型的连接池,由链接字符串来区分。打开一条连接,如果这条连接的类型签名与现有的连接不匹配,则创建新的连接池,反之不会创建,共用同一个连接池。
如何分配连接池?
在调用Open方法的时候根据连接请求的类型,找到与它相匹配的连接池(根据连接字符串来区分),有则在匹配到的连接池中尽力分配一条空闲的连接。如果已用完则会创建一个新的连接添加到连接池中,如果连接池已达到最大连接数,则会等待,直到有空闲的连接。
移除无效连接 不能正确的连接到数据库服务器的连接就移除,因为连接池中的连接数量大小有限,所以需要进行移除,否则浪费空间,这是由连接池管理器来处理的。
回收连接
使用完的连接应当立即释放或关闭,使用Close或者Dispose方法来实现。
ADO.Net默认是启用连接池的。连接字符串是可以控制连接池的行为的。比如:
Max Pool Size:最大连接数,默认100
Min Pool Size: 最小连接数,默认0
Pooling 是否启用连接池,默认true,否则设为false。
测试连接池的存在
#region 默认启用连接池并且最大数为5 { string connSQL = @"data source=.;initial catalog=TEST;persist security info=True;
user id=sa;password=123;MultipleActiveResultSets=True;Max Pool Size=5"; for (int i = 0; i < 10; i++) { SqlConnection sqlConnection = new SqlConnection(connSQL); sqlConnection.Open(); Console.WriteLine($"第{i + 1}个链接被打开"); } }
结果:
第1个链接被打开
第2个链接被打开
第3个链接被打开
第4个链接被打开
第5个链接被打开
所以在开启线程池之后,会遵循设置的连接池的最大数量,因为一直在创建,没有关闭,所以线程池中没有空闲连接了,就只能有5个。
示例2:不开启线程池
#region 默认不启用连接池,并且最大数为5 此时设置的最大连接数是无效的了 { string connSQL = @"data source=.;initial catalog=TEST;
persist security info=True;user id=sa;password=123;MultipleActiveResultSets=True;Max Pool Size=5;Pooling=false"; for (int i = 0; i < 10; i++) { SqlConnection sqlConnection = new SqlConnection(connSQL); sqlConnection.Open(); Console.WriteLine($"第{i + 1}个链接被打开"); } }
结果:
第1个链接被打开
第2个链接被打开
第3个链接被打开
第4个链接被打开
第5个链接被打开
第6个链接被打开
第7个链接被打开
第8个链接被打开
第9个链接被打开
第10个链接被打开
此时这10个连接都不是在连接池中取,全部都是现创建的,设置的最大数量管不了,但是这样的话比如连接池性能很差。
连接池类别区分测试
下面connSQL1与connSQL3的内容是一样的,connSQL2多了一个空格
#region 默认不启用连接池,并且最大数为5 此时设置的最大连接数是无效的了 { string connSQL1 = @"data source=.;initial catalog=TEST;persist security info=True;user id=sa;password=123;
MultipleActiveResultSets=True;Max Pool Size=5"; string connSQL2 = @" data source=.;initial catalog=TEST;persist security info=True;user id=sa;password=123;
MultipleActiveResultSets=True;Max Pool Size=5"; string connSQL3 = @"data source=.;initial catalog=TEST;persist security info=True;user id=sa;password=123;
MultipleActiveResultSets=True;Max Pool Size=5"; for (int i = 0; i < 5; i++) { SqlConnection sqlConnection1 = new SqlConnection(connSQL1); sqlConnection1.Open(); Console.WriteLine($"connSQL1 第{i + 1}个链接被打开"); SqlConnection sqlConnection2 = new SqlConnection(connSQL2); sqlConnection2.Open(); Console.WriteLine($"connSQL2 第{i + 1}个链接被打开"); SqlConnection sqlConnection3 = new SqlConnection(connSQL3); sqlConnection3.Open(); Console.WriteLine($"connSQL3 第{i + 1}个链接被打开"); } } #endregion
结果:
connSQL1 第1个链接被打开
connSQL2 第1个链接被打开
connSQL3 第1个链接被打开
connSQL1 第2个链接被打开
connSQL2 第2个链接被打开
connSQL3 第2个链接被打开
connSQL1 第3个链接被打开
connSQL2 第3个链接被打开
并且报了异常:超时已过。 在从池中获取连接之前超时时间已过。 这可能是因为所有池连接都在使用中并且达到了最大池大小
所以可以证明sqlConnection1和sqlConnection3使用的是同一个连接池,这2个连接已经全部瓜分了5条连接,并且全部都没释放。