• SqlDataReader的conn关闭问题(mysqldatareader),以及 ExecuteNonQuery,ExecuteScalar,ExecuteReader,SqlDataAdapter哪些需要conn.open


    之前觉得 using非常好用,什么都拿来using一下,返回datatable,返回dataset都用 using 来封装了 sqlconn和 sqlcmd,但是用这样的方法进行封装时,

    如果返回sqdatareader 则报错:“阅读器关闭时尝试调用 Read 无效”。

    这是因为出了using{}的作用域之后,conn连接自动关闭,而Reader与DataSet不同,DataSet已经将数据保存在本地内存中,所以不要conn连接也可以返回数据

    而Reader并没有将数据保存在本地内存中,可以理解成Reader只是指向了数据,连接关闭后用reader读取数据当然无法实现。

    如果你返回的是一个 SqlDataReader,那么在后台的 sqlhelper里面应该这样写

    #region PrepareCommand -> Command预处理,会判断conn的连接字符串是否已经指定,如果没有指定则使用默认web.config里面的字符串
            /// <summary>Command预处理
            /// </summary>
            /// <param name="conn">MySqlConnection对象</param>
            /// <param name="trans">MySqlTransaction对象,可为null</param>
            /// <param name="cmd">MySqlCommand对象</param>
            /// <param name="cmdType">CommandType,存储过程或命令行</param>
            /// <param name="cmdText">SQL语句或存储过程名</param>
            /// <param name="cmdParms">MySqlCommand参数数组,可为null</param>
            private static void PrepareCommand(MySqlConnection conn, MySqlTransaction trans, MySqlCommand cmd, CommandType cmdType, string cmdText, MySqlParameter[] cmdParms)
            {
                if (string.IsNullOrEmpty(conn.ConnectionString))
                {
                    conn.ConnectionString = DBConnectionString;
                }
                //到底什么时候需要conn.open呢?哪些操作需要open呢?
                //如果是通过cmd执行 ExecuteNonQuery,ExecuteScalar,ExecuteReader (也就是 类似于cmd.ExecuteNonQuery) 的时候,是需要open的
                //如果是通过MySqlDataAdapter da = new MySqlDataAdapter(cmd); 来执行的时候,是不需要open的,那么这个时候conn就一直开着吗?会浪费?
                //不会浪费,因为通过SqlDataAdapter的时候,我们都用using来封装了conn的 => using (MySqlConnection conn = new MySqlConnection(connectionString))
                //那么,没有封装using的 ExecuteReader 呢?也是一直开着?放心,我们有用到 MySqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            //这样,当 dr 关闭的时候, conn也会跟着关闭了(如果前台调用是用dr.Read()来获取值,则需要dr.Close关闭,如果是gridview之类的控件绑定, 则不用dr.Close了)  
                if (conn.State != ConnectionState.Open)
                    conn.Open();
    
                cmd.Connection = conn;
                cmd.CommandText = cmdText;
    
                if (trans != null)
                    cmd.Transaction = trans;
    
                cmd.CommandType = cmdType;
    
                if (cmdParms != null)
                {
                    foreach (MySqlParameter parm in cmdParms)
                        cmd.Parameters.Add(parm);
                }
            }
            #endregion
    

     

    #region ExecuteReader ->执行命令或存储过程,返回MySqlDataReader对象
            /// <summary>
            /// 执行命令或存储过程,返回MySqlDataReader对象
            /// 注意MySqlDataReader对象,在前台使用完最好是先弄一个dr等于这里的返回值,
            /// 如果前台调用是用的dr.Read(),然后读取的值,则之后需要对dr进行dr.Close以关闭dr,进而释放MySqlConnection资源
            /// 如果是绑定了gridview之类的控件,则不用dr.Close(绑定控件帮我们已经close了)
            /// </summary>
            /// <param name="connectionString">连接字符串,可为null,如果为null则使用web.config的值,不为null则使用传入的值</param>
            /// <param name="cmdType">命令类型(存储过程或SQL语句)</param>
            /// <param name="cmdText">SQL语句或存储过程名</param>
            /// <param name="cmdParms">MySqlCommand参数数组</param>
            /// <returns></returns>
            public static IDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] cmdParms)
            {
                MySqlCommand cmd = new MySqlCommand();
                MySqlConnection conn = new MySqlConnection(connectionString);
    
                try
                {
                    PrepareCommand(conn, null, cmd, cmdType, cmdText, cmdParms);
                    MySqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);    
                    cmd.Parameters.Clear();
                    return dr;
                }
                catch
                {
                    conn.Close();
                    throw;
                }
            }
            #endregion
    

    在这里,要注意,我们写了 一句  MySqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);  

    这个的作用是"关闭SqlDataReader 会自动关闭Sqlconnection." 也就是说,关闭Sqlconnection是在关闭SqlDataReader的前提下进行,所以还是需要我们手动关闭SqlDataReader。

    又要返回SqlDataReader,又要关闭它,怎么办呢?要看你调用的时候是如何使用的

    假如你前台是用 dr.read() 这样循环来使用的,则需要你手动关闭  ( dr.Close() )

    下面的例子就是使用一个dr.Read(),循环获取dr里面的值,我们看到dr在循环的时候,是没有关闭的,那,循环完毕之后呢?

    image

    循环之后,也还是没有关闭的,所以需要我们用 dr.Close() 来进行手动关闭,最好是

    if (dr != null)
               {
                   dr.Close();
               }
    

    image

    这样就OK了,就可以解决dr的关闭了。

    题外话,如果又有 dr.read(),后面又想再拿来绑定个什么什么控件呢?关闭了之后还能绑定么?比如绑定到 下拉列表,还能执行么?

    image

    显然是不能执行,因为我们在用dr进行绑定的时候,dr是不能关闭的。

    image

    假如你前台使用的是 gridview,下拉控件之类的绑定,则不用你手动关闭

    image
    这里可以很清楚的看到,当执行完 绑定之后,dr就被自动关闭了,那么sqlhelper里面的conn也因为CommandBehavior.CloseConnection 会自动关闭conn

    image

    参考文档   mysqlhelper帮助类:http://www.cnblogs.com/joeylee/archive/2012/10/19/2731366.html

    http://blog.csdn.net/xiaoman880626/article/details/6684829

    http://www.cnblogs.com/denny402/archive/2011/04/05/denny.html

  • 相关阅读:
    这个博客的由来
    PLSQL Developer 不能连接 oracle 12c 64位 的解决办法 for win 64
    Netflix 是如何推荐电影的
    Hadoop中国技术峰会引发Hadoop 2.0风暴
    JS如何导出Div的内容为图片
    jquery如何获取标签本生的文本内容,不获取本身子级元素及子级元素的内容
    superagent抓取gb2312网页出来是十六进制的解决办法
    一些常见html css遇到的问题
    es6 三行代码数组去重
    es6中的 Set、Map 和 WeakMap
  • 原文地址:https://www.cnblogs.com/joeylee/p/2802754.html
Copyright © 2020-2023  润新知