.net读取数据集有两种方式:DataSet 和 DataReader
孰优孰劣我们暂且不论,我在做项目纯读取数据的时候选用了DataReader。
首先我确认用完之后关闭了,百分百确认。 reader,connection都close了,甚至都dispose了。
但是出现一个很奇怪的问题:
在sqlserver(2000)中查看进程,有非常多的sleeping进程,直到最后打开页面,提示超时,说连接池满。
错误提示:"超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小 "
1.我在连接字符串里加上了Pooling=false禁用了连接池,仍会出现上述问题,说明这些sleeping是sqlserver内部机制管理的。
2.当提示 "超时,说连接池满" 的时候,任然有很多sleeping的连接。
解决:将项目中所有使用DataReader的地方改用DataSet ,则不会再出现这个问题。
疑问:
1.为什么会出现这种情况,是否是因为DataReader本身的问题?如果是,那稍大并发的项目就不能用DataReader了。
2.有没有可能是sqlserver2000 本身的问题?
3.提示 超时,说连接池满 的时候,任然有很多sleeping的连接。 既然有空闲连接,为什么不用?
求各位大牛不吝指教!
-----------------------------------------
有博友说让贴代码,没有代码的确不好分析,但是项目中的代码是分层分散不太好贴。
我自己写了简单的测试,使用多线程模拟并发测试,也会出现上述问题。
代码如下:
string conString = "Server=.;database=northwind;user id=reader;password=123456;"; SqlConnection con = new SqlConnection(conString); SqlCommand cmd = new SqlCommand(); con.Open(); cmd.Connection = con; cmd.CommandText = "select * from Customers"; cmd.CommandType = CommandType.Text; using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { while (reader.Read()) { Thread.Sleep(30); } reader.Close(); reader.Dispose(); con.Close(); con.Dispose(); }
SAFASDFSADFASDFSADFSDFS DFSADF SADF ASDF
我很像知道你的DataReader是怎么写的? 什么问题都是有原因的,很多时候你得到的结论不一样,不一定是你确定的那样。
使用的是微软官方的数据库操作类,使用的是最基础的SqlDataReader.
datareader用完之后要关闭。
我百分百确定关闭了。包括Connection也关闭了,甚至都Dispose了,仍然如此。
@亻寸 日月 月月鸟:
贴代码
@亻寸 日月 月月鸟:
不会啊,没发现你这代码里有问题。
我之前也遇到了这样的情况,后来就再也没用过DataReader,代码看起来真的没什么问题,打开,关闭都正常,单只有一个或两个用户操作时没问题,但用户多了以后,就出现这两种情况:1.DataReader关闭 2.连接超时;到现在也没明白是怎么回事。。。期待高手解答。。。
建议楼主把下面的代码去掉,因为使用Using没必要手动释放,con.Close()应该写在Using外面,而且cmd也要释放。
reader.Close();
reader.Dispose();
con.Close();
con.Dispose();
SqlDataReader是持久性连接,读取数据会一直保持数据库连接状态。建议你把con.Close()放在using外关闭,并且有可能是同时访问量人数超出数据库连接池最大限制造成的。看下这个对你有用没?http://topic.csdn.net/u/20100421/15/c308f282-c2e4-409e-889a-95d08fb43568.html,还有这个http://blog.csdn.net/lee576/article/details/2116360
string conString = "Server=.;database=northwind;user id=reader;password=123456;"; using (SqlConnection con = new SqlConnection(conString)) { SqlCommand cmd = new SqlCommand(); con.Open(); cmd.Connection = con; cmd.CommandText = "select * from Customers"; cmd.CommandType = CommandType.Text; SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (reader.Read()) { Thread.Sleep(30); } reader.Close(); reader.Dispose(); con.Close(); }
改成这样再试试看?
1.怎么会,想要性能好一点,数据库连接是即用即关。使用连接的时间也应该尽量短。Reader是要保持连接的,不用维护DataSet的相对较大的内存开销。DataSet是一次性取回的,与连接无关。这个随便哪个文档都应该说的很清楚的。因此DataReader和DataSet应该各有各用到的地方。2.Sql2000本身没问题。3.那个Sleeping的连接也不一定是连接池能够掌握的。
你可以将连接的打开和关闭写入日志,然后再看看。您的程序的问题可能是1,没有将使用连接的时间保持在尽量短,2. 没有分层,导致出现许多不必要的数据库存取操作,加重了数据库的负担。
.net sql的连接池是隐式管理的。是针对连接字符串建立的连接池。你即使关了连接也只是业务上的关闭,对连接池没有影响的。
楼主把using 去掉呢。
首先,DataReader本身没有任何问题
DataSet也是由DataReader灌入的。
关键在于你用DataReader读取时,不能有耗时操作!!!
while (reader.Read()) { Thread.Sleep(30);//这里不能有逻辑操作,应该直接赋值就走(100条数据就3秒啊!!!这可不是小数目,查出来灌到dataset中都不会这么久) }
其次,连接池的连接关闭后是不会立即被其他线程启用的。
你可以这样试试:
构建一个command,
循环执行一个简单的update语句,
每次执行完之后重新实例化Connection
然后你检测sql会发现,新建了很多连接。。
why? 就是因为连接池本身的逻辑处理是有一定耗时的,不能保证刚关闭的connection会立即被启用
不过我不明白你怎么会有那么多的并发访问,
要知道一个页面不太可能在几毫秒内被调用多次(除非taobao之类的)
所以你要测试的话,应该是按照吞吐量,每分钟发多少次请求测试,而不是秒级的测试