DataReader 连接关闭解惑篇

日期
2011/4/7
关键字
,

大伙对DataReader的连接关闭问题比较迷惑,某某领导人说:实践是检验真理的唯一标准。因为以代码说话,给大家讲明白应该怎么使用DataReader,什么情况下要自己关闭连接。
不管是啥xxDataReader,都是继承DataReader实现的,所以是有共性的,因此标题就以DataReader为题了。

情况一:DataReader 默认链接不关闭
示例代码:

static void Main(string[] args)
{
    SqlConnection con = new SqlConnection("server=.;database=MySpace;uid=sa;pwd=123456");
    con.Open();
    SqlCommand com = new SqlCommand("select top 1 id from blog_user",con);
    SqlDataReader sdr = com.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
    while (sdr.Read())
    {
    }
    Console.WriteLine(sdr.IsClosed);
    Console.WriteLine(con.State.ToString());
    Console.ReadLine();
}

输出结果是:
False
Open
说明:默认无论是不是加System.Data.CommandBehavior.CloseConnection,读取时数据库链接不会帮你关闭。
 

情况二:DataReader 链接已关闭
示例代码:

protected void bind()
{
    SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["constr"].ToString());
    conn.Open();
    SqlCommand cmd = new SqlCommand("GetAllUser", conn);
    SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
    repeater1.DataSource = sdr;
    repeater1.DataBind();
    Response.Write(sdr.IsClosed.ToString() + "<br/>");
    Response.Write(conn.State.ToString());
}

 

输出结果是:
True
Closed
状况:System.Data.CommandBehavior.CloseConnection加完之后,链接给你关闭了,为啥?看下面的分析原因。

三:原因分析
1:从前面的两个示例上看,区别是什么?
答:区别就在于一个只读数据,另一个绑定了数据列表控件。

2:为什么绑定了数据列表控件就会自动关闭链接?
答:这就涉及到数据控件绑定机制了,这里给大伙简单介绍一下:
A:要实现数据控件列表绑定,有一个接口是需要实现的:IEnumerable
B:实现DataReader实现此接口的代码[基类���抽象方法,所以只能到子类SqlDataReader查看]:

public override IEnumerator GetEnumerator()
{
    return new DbEnumerator(this, (this._commandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection);
}


从代码看,我们只看到了它把CloseConnection传进DbEnumerator里了,再进去看一下:

public DbEnumerator(IDataReader reader, bool closeReader)
{
    if (reader == null)
    {
        throw ADP.ArgumentNull("reader");
    }
    this._reader = reader;
    this.closeReader = closeReader;//此行设置了标志
}

点进去只看到构造函数,并把它赋给this.closeReader属性,因为DataReader是向前读方式,所以重点还是要看其中的一个方法MoveNext:

public bool MoveNext()
{
    if (this._schemaInfo == null)
    {
        this.BuildSchemaInfo();
    }
    this._current = null;
    if (this._reader.Read())//此方法被调用一次,就读一次
    {
        object[] values = new object[this._schemaInfo.Length];
        this._reader.GetValues(values);
        this._current = new DataRecordInternal(this._schemaInfo, values, this._descriptors, this._fieldNameLookup);
        return true;//有数据时直接返回,不会执行下面的关闭链接
    }
    if (this.closeReader)//好,能进行这里,说明上面读不到数据,简说就是数据读完了
    {
        this._reader.Close();//关闭链接操作。
    }
    return false;
}

C:毛主席说,不以结婚为目的的恋爱就是耍流氓,引用一下,使用DataReader作为数据源来绑定列表控件就是耍流氓!
原因:一个页面通常会有很多个服务器控件,而服务端控件列表渲染出表格的周期通常比较长,所以,只有到你看到最后结果列表出来的时候,最后一行数据才读完。
因此链接是持续相当长的处于打开状态,所以web这种并发多的情况,狂点几下,估计就报错了,连接池用满了。

四:最终结论是什么?
1:在绑定列表控件时,只要数据行读取完毕,就会自动关闭链接。
2:在直接读取时,不会触发绑定相关的读取,所以不会自动关闭链接。
3:在绑定列表控件时,链接长期得不到关闭,并发一来,就挂了,因此大伙就不要耍流氓了。

希望本文对你有所帮助。
原文链接:http://www.cnblogs.com/cyq1162/archive/2011/04/06/2006412.html

0 评论

添加评论

  Country flag

biuquote
  • 评论
  • 在线预览
Loading