非常老的话题 SQLSERVER连接池
非常老的话题 SQLSERVER连接池
写这篇文章不是说要炒冷饭,因为园子里有非常非常多关于SQLSERVER连接池的文章,但是他们说的都是引用MSDN里的解释
或者自己做一些测试试验一下连接池的性能。但是对于SQLSERVER连接池的内部机制,好像都没有非常清晰地说清楚。
连接池的作用就不说了,在园子里随便搜一大堆
还有使用连接池有利也有弊,大部分文章都说连接池的好处没有说连接池的不好的地方
连接池不好的地方在于事务的提交方面,如果上一个连接没有提交事务,有可能下一个
连接会遇到因为上一个连接的事务没有提交从而遇到意想不到的后果
详细的可以自行GOOGLE
先说一下带连接池功能的编程接口
微软的SQLSERVER客户端编程接口:
ADO和ADO.NET 都支持连接池这种机制
JAVA的JDBC也支持连接池这种机制
注意:连接池机制是客户端数据库驱动程序提供的,功能都在驱动程序里,所以JDBC跟ADO,ADO.NET的连接池功能会有区别
因为客户端应用程序都是通过加载SQLSERVER的数据驱动控件做SQLSERVER连接。目前客户端数据库驱动程序主要有3种:
1、MDAC(微软数据访问组件) SQL2000的时候开始有的
2、SQLSERVER Native Client SQL2005开始引入的
3、Microsoft JDBC Provider 使用机制与MDAC和SQLSERVER Native Client不同
下面再说一下在论坛里经常有人问到的问题:
问题1:SQLServer连接池被创建在SQLClient端还是SQLServer端?
答案:在客户端
当应用程序运行的时候,会有一个连接池的管理控件运行在应用程序的进程里,统一管理应用程序和SQLSERVER建立的所有连接,
并且维护这些连接一直处于活动状态。当有用户发出一个connection open指令时连接池会在自己维护的连接池中找一个处于空闲状态
的连接放回自己管理的连接池里,给这个用户使用。当用户使用完毕后,发出connection close指令,连接池会把这个连接放回自己
管理的连接池里,让他重新处于空闲状态,而不是真的从SQL里登出。这样如果下次有用户需要相同连接,就可以重用这个连接,
而无须再去做物理连接了。就是说连接池是放在客户端的,是客户端机制
问题2:如果在一个应用程序里设置连接池的大小为40000个,第二个应用程序里设置连接池的大小也为40000个,
程序跟SQLSERVER会不会报错?
答案:不会
当应用程序运行的时候,会有一个连接池的管理控件运行在应用程序的进程里,统一管理应用程序和SQLSERVER建立的所有连接,
并且维护这些连接一直处于活动状态。当有用户发出一个connection open指令时连接池会在自己维护的连接池中找一个处于空闲状态
的连接放回自己管理的连接池里,给这个用户使用。当用户使用完毕后,发出connection close指令,连接池会把这个连接放回自己
管理的连接池里,让他重新处于空闲状态,而不是真的从SQL里登出。这样如果下次有用户需要相同连接,就可以重用这个连接,
而无须再去做物理连接了
这个问题是针对上面这段话的,如果一个应用程序指定了连接池的大小为40000个那么跟SQLSERVER的连接已经有40000个了,
SQLSERVER的最大连接数是32767,那么第二个应用程序再打开40000个连接会不会报错呢?
本人根据园子里的这篇文章做了一个实验测试会不会报错,修改了他里面的一些代码,下面是我自己写的代码跟报错的内容跟文章链接
做实验之前记得重启一下SQLSERVER
亲测SQLServer的最大连接数
http://www.cnblogs.com/wlb/archive/2012/04/08/2437617.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient; namespace SQLServerMaxConnectionTest
{
class Program
{
static void Main(string[] args)
{
int maxCount = ;
string connstr="Server=joe;Database=AdventureWorks;User ID=sa;Password=test;pooling=true;connection lifetime=0;min pool size = 1;max pool size=40000";
List<SqlConnection> collection = new List<SqlConnection>();
for (int i = ; i < maxCount; i++)
{
Console.WriteLine(string.Format("成功创建连接对象{0}",i));
try
{
var db = new SqlConnection(connstr);
db.Open();
collection.Add(db);
}
catch (Exception ex)
{
WriteErrLog.AppendErrLog(ex.ToString());
} }
}
}
}
-- :: System.Data.SqlClient.SqlException: 当前命令发生了严重错误。应放弃任何可能产生的结果。
在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
在 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
在 System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
在 System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject)

由于本人的笔记本性能不给力,在cmd里面打开的对象数达到16531 另一个是16124的时候差不多死机了,所以未能截图。
16531+16124 差不多达到32767,测试结果表明,如果有程序一早打开了一定数目的连接,那么第二个应用程序就算
再打开40000个连接是没有用的并会报错,第二个应用程序能打开的连接数目等于SQLSERVER最大连接数减去第一个应用程序
打开的连接数
有一个问题非常奇怪:两个应用程序都可以指定连接池的最大连接数为40000,如果是这样的话应该SQLSERVER应该预先
保持了80000个活动连接,让应用程序连接进来,这样SQLSERVER应该会报错,但是我用下面代码测试了,发现没有报错
测试方法跟上面的那个测试一样,做下面实验之前请重启一下SQLSERVER
这个问题已经有答案了,答案在文章的结尾o(∩_∩)o
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient; namespace SQLServerMaxConnectionTest
{
class Program
{
static void Main(string[] args)
{
//改成500个连接
int maxCount = ;
string connstr="Server=joe;Database=AdventureWorks;User ID=sa;Password=test;pooling=true;connection lifetime=0;min pool size = 1;max pool size=40000";
List<SqlConnection> collection = new List<SqlConnection>();
for (int i = ; i < maxCount; i++)
{
Console.WriteLine(string.Format("成功创建连接对象{0}",i));
try
{
var db = new SqlConnection(connstr);
db.Open();
collection.Add(db);
}
catch (Exception ex)
{
WriteErrLog.AppendErrLog(ex.ToString());
} }
}
}
}
希望高人可以解答一下
问题3:连接池字符串里要不要写pooling=true;connection lifetime=0;min pool size = 1;?
答案:个人觉得没有必要写,连接池默认是开启的,连接的生命周期没有必要指定,因为你都不知道
自己的SQL语句要运行多长时间,连接池的min pool size不需要指定了,只需要指定max pool size=32767
就可以了
问题4:sp_reset_connection 经常有人在论坛里问,使用SQL Trace的时候会有大量的sp_reset_connection
这个存储过程的执行,这个存储过程到底是什么来的?
网上对这个存储过程的资料很少,MSDN也找不到资料
答案:我们知道,每个连接都会维护自己的一些独有资源,比如临时表,变量,游标等,
他也有可能会修改一些默认的设置,例如事务隔离级别等。如果不同用户先后使用同一个连接,
会不会前一个用户设置的状态或申请的资源影响后一个用户正常使用呢?如果连接池的管理者
不做特殊处理,的确会有这种情况发生。所以微软的连接池技术里包括ADO.NET和ADO,
引入了一个特殊的指令:sp_reset_connection,来清除前一个用户做的绝大多数设置,避免这种问题。
sp_reset_connection会在SQLSERVER里做些什么?
1、清除连接现有所有内部数据结构。包括:
(1)清除所有openxml打开的document句柄
(2)关闭所有的游标(cursor)
(3)释放所有SQL语句句柄
(4)清除所有临时对象(临时表等)
(5)释放连接持有的所有锁
(6)清除缓存的所有安全上下文信息(security context)
2、重置连接设置。包括:
(1)重置连接的SQL Trace标志值(例如1204,1222,3604等)
(2)重置所有"SET" 选项值(SET IMPLICIT_TRANSACTIONS ON 等)
(3)重置连接的统计信息值
3、回滚所有SQLSERVER事务
需要说明的是,如果连接当前参与了一个由客户端发起的分布式事务,这个分布式事务不会受到影响。
在SQL里的事务还会被保留
4、把当前数据库切换到用户默认数据库
5、SQLSERVER会再次检查当前用户是否有权做数据库连接。如果这个权力已被移除
SQLSERVER会中断这个物理连接(这样防止一个已经被取消访问权的用户还能长时间
使用数据库的问题)
完成这些事情以后,一个连接基本上已经和他先前做的事情不再有任何关系(分布式事务除外)
可以说,这个连接和一个新的连接已经没有什么大的区别了。通过这些,应用程序的用户
可以尽快地拿到和释放连接,而SQLSERVER这边也不会因为连接的重复使用而产生相互影响的问题
准备下班了 有问题的童鞋可以发评论,希望大家拍砖o(∩_∩)o
刚才测试了一下,在SSMS里运行下面语句
SELECT [program_name] ,[spid] FROM [sys].[sysprocesses] WHERE [spid]>50
然后运行上面我给出的示例代码程序跟SQLSERVER都在同一台电脑,改为500个连接那个,我双击打开了很多个cmd程序,
发现在cmd程序运行的时候会看到大量的连接在SSMS里面

当那些cmd程序全部运行完毕之后,这些进程就在SQLSERVER里消失

那么上面的问题:
两个应用程序都可以指定连接池的最大连接数为40000,如果是这样的话应该SQLSERVER应该预先
保持了80000个活动连接,让应用程序连接进来,这样SQLSERVER应该会报错
答案:应该是连接池保持了80000个活动连接,SQLSERVER并没有保持这些活动连接
想一想这也是正确的,如果客户端指定了80000个连接,SQLSERVER就要一次打开
80000个连接(实际数量是32767个)并对这些连接进行维护,那么SQLSERVER肯定
慢得要命。因为客户端的连接并没有达到80000个那么多,你在连接字符串里指定80000个
连接,实际上只是指定连接池的连接数
客户端的连接池和服务器端的线程池的区别
客户端连接池即使是40000个,也只是一个设定值,并不是说当前程序打开了40000个长连接

即使真的有40000个连接到SQL Server,SQL Server同一时刻也只能保持32767个长连接
非常老的话题 SQLSERVER连接池的更多相关文章
- SQLSERVER连接池内部机制
前言介绍: 当应用程序运行的时候,会有一个连接池的管理控件运行在应用程序的进程里,统一管理应用程序和SQLSERVER建立的所有连接, 并且维护这些连接一直处于活动状态.当有用户发出一个connect ...
- hibernate+mysql的连接池配置
1:连接池的必知概念 首先,我们还是老套的讲讲连接池的基本概念,概念理解清楚了,我们也知道后面是怎么回事了. 以前我们程序连接数据库的时候,每一次连接数据库都要一个连接,用完后再释放.如果频繁的 ...
- SqlServer 连接 相关。
sqlserver数据库连接池是一个客户端的东西.和sql server服务器无关. 各种provider默认的连接池大小不同. 比如:Ado.NET 中sqlserver 连接池默认的值是100. ...
- 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法
本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...
- 最近学习了Http连接池
起因 6.1大促值班发现的一个问题,一个rpc接口在0~2点用户下单高峰的时候表现rt高(超过1s,实际上针对性优化过的接口rt超过这个值也是有问题的,通常rpc接口里面即使逻辑复杂,300ms应该也 ...
- C3P0连接池在hibernate和spring中的配置
首先为什么要使用连接池及为什么要选择C3P0连接池,这里就不多说了,目前C3P0连接池还是比较方便.比较稳定的连接池,能与spring.hibernate等开源框架进行整合. 一.hibernate中 ...
- DBCP连接池配置参数说明
<!-- 数据源1 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicData ...
- 功能完善的Java连接池调用实例
/** * Title: ConnectPool.java * Description: 连接池管理器 * Copyright: Copyright © 2002/12/25 * Company: * ...
- 几个主流java连接池
池(Pool)技术在一定程度上可以明显优化服务器应用程序的性能,提高程序执行效率和降低系统资源开销.这里所说的池是一种广义上的池,比如数据库连接池.线程池.内存池.对象池等.其中,对象池可以看成保存对 ...
随机推荐
- CentOS 6.3安装配置LAMP服务器(Linux+Apache+MySQL+PHP5)
服务器系统环境:CentOS 6.3 客户端系统环境:Windows 7 ultimate(x86)sp1 简体中文旗舰版 ※ 本文档描述了如何在Linux服务器配置Apache.Mysql.PHP ...
- [muku][1 初始restful api] chorme安装jsonview 插件
https://github.com/gildas-lormeau/JSONView-for-Chrome https://www.cnblogs.com/androidstudy/p
- [错误解决]pandas DataFrame中经常出现SettingWithCopyWarning
先从原dataframe取出一个子dataframe,然后再对其中的元素赋值,例如 s = d[d['col_1'] == 0] s.loc[:, 'col_2'] = 1 就会出现报错: Setti ...
- 团队Alpha版本(五)冲刺
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- Android 开发中Service完全解析
定义:服务,是Android四大组件之一,属于计算型组件 作用:提供 需在后台长期运行的服务 生命周期: 在Service的生命周期里,常用的有: (1) 4个手动调用的方法 手动调 ...
- VMware ESXI 5.5 注册码
VMware ESXI 5.5 注册码 ESXI 注册码0A42V-8M182-3ZZ88-R21N6-32K5H ESXi Server许可证类型产品: Mware vSphere 5 Enterp ...
- BZOJ4888 [Tjoi2017]异或和 【树状数组】
题目链接 BZOJ4888 题解 要求所有连续异或和,转化为任意两个前缀和相减 要求最后的异或和,转化为求每一位\(1\)的出现次数 所以我们只需要对每一个\(i\)快速求出\(sum[i] - su ...
- [TJOI2007] 线段 (动态规划)
题目链接 Solution 传统的线性 \(dp\) . \(f[i][0]\),\(f[i][1]\) 分别表示最后一次在 \(i\) ,然后在 左边或者右边的最小步数. 然后就每次根据上一次左边和 ...
- js对象和jq对象互相转换
1.DOM 对象转成 jQuery 对象 var v = document.getElementById("v"); //DOM对象 var $v = $(v); //jQuery ...
- SpringMVC+MyBatis+Shiro 配置文件详解
1.web.xml文件的配置 <?xml version="1.0" encoding="UTF-8"?> <web-app version= ...