zoukankan      html  css  js  c++  java
  • 每日学习总结:"已有打开的与此命令相关联的 DataReader,必须首先将它关闭。"、Sql Server 连接池机制

    2013-5-25

    1.    已有打开的与此命令相关联的 DataReader,必须首先将它关闭。"问题.

    上周在项目开发中,遇到这样的一个问题,在前台展示页,两个WebPart调用后台的API进行数据的查询呈现。有时候两个数据报表都能呈现,而有时候,却只能呈现一个报表。使用IE的开发人员调试工具跟踪调试以后,发现了如上提到的问题“已有打开的与此命令相关联的 DataReader,必须首先将它关闭”。

    起先以为是API中使用了DataReader进行数据读取,没有关闭,检查了一下代码,发现代码中并没有使用DataReader,然后,以为是SqlConnection没有关闭,又检查了下代码,发现所有的SqlConnection在使用完之后都进行了关闭,只不过在DBHelper(数据库访问类)里边SqlConnection数据库连接对象是一个静态的全局变量。如此这样检查了几遍仍是会报出这样的错误。

    在网上查找了一些资料以后终于找到了问题之所在。原来在SqlCommand在每次执行ExecuteNonQuery()方法之后,内部会生成一个空的DataReader对象,该对象只有在数据库连接关闭之后,才会被释放掉,加上上边提到的,在DBHelper类中数据库连接对象是一个静态的全局变量。因为在同时调用API进行数据查询时,在第一个查询还未结束,数据库连接对象还未关闭,第二个查询却已经开始查询,所以才会出现DataReader没有关闭的情况。

    那么该如何解决上边的问题呢?

    方法有三:

    第一种方法:

    使用using的形式:

    Using(SqlConnection sqlConn=new  SqlConnection(“数据库连接字符串”)

    {

    sqlConn.Open();

    SqlCommand com=new SqlCommnand(sqlCon,”sql”);

    /执行访问数据库操作代码

    }

    Using指定了SqlConnection的对象作用的范围,且是独占使用的,当使用结束之后会自动将其进行释放,所以也就很好的解决了上边的问题,即使是同时多次访问,也不会有DataReader未关闭的情况,因为只有一次访问完,释放之后才会进行下一次的访问。

    第二中方法:

    在数据库连接字符串中添加MultipleActiveResultSets=true即可,示例如下:

    server=.;Integrated Security = true;database=Test;MultipleActiveResultSets=true;

    SQL Server数据库默认的只有一个活动的SqlDataReader,如果想要一个连接允许多个SqlDataReader,那就需要将MultipleActiveResultSets设置为true,其意义为:将数据库连接设置可复用,即可供多个SqlCommand同时使用。

    如果在 MARS 连接下提交两个批处理,一个批处理包含 SELECT 语句,另一个包含 DML 语句,DML 可以在 SELECT 语句执行过程中开始执行。 但是,DML 语句必须运行完成,SELECT 语句才可以继续执行。 如果两个语句在相同事务下运行,读取操作将看不到 DML 语句在 SELECT 语句开始执行后所作的任何更改。

    如果打开了启用了MARS会话连接,会创建一个逻辑会话,增加系统的开销,为了减小系统开销提升系统性能,SqlClient会将对MARS对话缓存在连接内,做多可缓存10个对话。

    MARS的操作不是线程安全的。如果应用程序打开了两个连接一个为MARS连接一个为一般连接,则这两个连接分别位于独立的连接池中。使用MARS之后,并非不再需要在应用程序中使用多个连接,如果应用程序需要对服务器真正的执行并行命令,还是需要建立多个连接的。

    所以,总的来说,虽然这种方法很简单,也能解决问题,但是还是不推荐使用这种方法的。

    第三种方法:

    之所以会出现上边报出的错误,往往都是因为数据连接对象是静态、全局的对象,相应有很多朋友为了避免多次的声明、创建对象,干脆将该数据连接对象设置为静态的全局的,这样做的确可以省下不少的功夫,但是带来的弊端也是显而易见的,也就是再高并发操作的情况下,会出现上边提到的错误。

    因此,这里建议,将数据连接对象设置为局部的,且每次都new一个对象出来,这样做不过是多创建了几个对象,开了几个连接罢了,但是,即使是高并发也不会出现DataReader未关闭的情况。此外,事实上只有在第一次进行数据连接比较耗费时间和性能之外,以后进行的连接操作,所耗费的时间几乎是可以忽略不计的,因为SqlConnection还有连接池的机制,这也是下边要讲的一个内容。

    2.    Sql Server 连接池机制

    在上一小节的最后提到了,只有在首次进行数据库连接比较耗费时间和性能之外,以后的连接时间几乎可以忽略不计,这主要是因为有了数据连接池的原因。

    在首次连接时,因为需要解析字符串、授权、检查、和服务器握手等操作,所以相对来讲需要耗费一点时间,但是在首次连接建立之后,这些繁琐的操作便不会再做了,因为有了连接池机制,SqlConnection默认的开启了连接池的功能,也就是说当程序执行SqlConnection.Close()方法后,连接并不会被立即释放到,而是被存到了连接池中,当下一次再有连接请求时,直接从连接池中调出该连接即可。所以在首次连接成功之后的一段时间内,再次对数据库进行连接时,连接过程时不耗费任何连接时间的,但是,如果过了20分钟之后再去进行数据库的连接,这个时候,连接时间又会和首次连接所耗费的时间一样长。这是因为连接池和Season一样都会过期的,超过了一定的时间,就会被收回,一般默认的时间为5-10分钟,如果在此期间没有任何的连接数据库操作,该连接就会被释放。

    有没有只需一次连接,变永远的保持连接状态不变的方法呢?事实上,在连接池中有一项设置为最小连接池大小,默认为0,只需将其值设置为大于0 即可永久的保持连接。

    示例如下:

    Data Source=.; Initial Catalog=Test; Integrated Security=True;Min Pool Size=1

    有关多线程访问的问题(通过new SqlConnection()方式访问),如果后一个线程在前一线程关闭之前进行Open()操作,那么此时会创建一个新的物理连接,反之,后一个线程会使用前一个线程的物理连接。但是在实际的运用中,往往会有并发的情况出现,为了尽可能少的创建新的物理连接,我们可以将Min Pool Size的值适当的设的大一些,这样会适当的减轻服务器的压力。

    好了,还有些没总结完,但是今天太累了,就先到这儿吧,希望能给大家带来一些帮助。

  • 相关阅读:
    卡特兰数
    hdu 1023 Train Problem II
    hdu 1022 Train Problem
    hdu 1021 Fibonacci Again 找规律
    java大数模板
    gcd
    object dection资源
    Rich feature hierarchies for accurate object detection and semantic segmentation(RCNN)
    softmax sigmoid
    凸优化
  • 原文地址:https://www.cnblogs.com/Olive116/p/3099516.html
Copyright © 2011-2022 走看看