zoukankan      html  css  js  c++  java
  • SqlHelper类编写前奏:DataReader关闭链接出现问题

    SqlHelper是一个执行数据库操作的助手类,但是当我们没学过DataSet之前,要想使用using搭配SqlConnection和SqlCommand写出一个真正独立的SqlHelper都是不太可能的。

    比如:一个常规的ExecuteReader方法如果使用上述做法,代码如下:

    using System.Data.SqlClient;
    
    namespace ExecuteScalar.libs
    {
        class SqlHelper
        {
            public static SqlDataReader ExecuteScalar()
            {
                //使用using管理资源
                using (SqlConnection conn = new SqlConnection("server=.;database=WebSite;uid=sa;pwd=123456"))
                {
                    using (SqlCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = "select * from UserInfo";
                        conn.Open();
    
                        return cmd.ExecuteReader();
                    }
                }
            }//end ExecuteScalar
    
        }
    }

    我们在窗体的按钮点击事件中使用这个类的ExecuteScalar方法获取的SqlDataReader对象

    private void button1_Click(object sender, EventArgs e)
    {
        //使用dr变量接收ExecuteReader方法产生的SqlDataReader对象
        SqlDataReader dr = libs.SqlHelper.ExecuteReader("select * from UserInfo");
    
        MessageBox.Show(dr.HasRows.ToString());
    }

    执行点击事件,发现代码报异常:阅读器关闭时尝试调用 HasRows 无效 

    因为使用using在using的作用域结束之前会自动调用Dispose方法,导致连接关闭。而SqlDataReader对象读取的是服务器的数据,你通过ExecuteReader返回的一个SqlDataReader对象值保存了指向服务器结果集的指针并没有数据,数据还是要依赖于conn来读取的。结论:因此这里不能使用using

    既然不using,自然不会报错,conn释放资源怎么办呢。于是就想到了这种办法

    using System.Data.SqlClient;
    
    namespace ExecuteScalar.libs
    {
        class SqlHelper
        {
            //将conn定义为静态成员,要可以在外部手动释放掉
            public static SqlConnection conn;
    
            public static SqlDataReader ExecuteScalar()
            {
                //使用using管理资源
                using (conn = new SqlConnection("server=.;database=WebSite;uid=sa;pwd=123456"))
                {
                    using (SqlCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = "select * from UserInfo";
                        conn.Open();
    
                        return cmd.ExecuteReader();
                    }
                }
            }//end ExecuteScalar
    
        }
    }

    使用的时候可以这样用:

    private void button1_Click(object sender, EventArgs e)
    {
        //使用dr变量接收ExecuteReader方法产生的SqlDataReader对象
        SqlDataReader dr = libs.SqlHelper.ExecuteReader("select * from UserInfo");
    
        MessageBox.Show(dr.HasRows.ToString());
        //关闭SqlDataReader
        dr.Close();
        libs.SqlHelper.conn.Close();
    
    }

    这样就达到了释放conn链接资源的目的。

    且不说这种方法多么的不规范,多么违背面向对象程序设计的思想。光说这个手动释放,有多少程序员能够准确记得这一步。

    这样的做法不能使SqlHelper成为一个真正独立真正封装的类。

    基于此,我们就该在SqlHelper中放弃using 和 SqlDataReader的搭配。转而使用DataSet和SqlDataAdapter方式。

    DataSet就是一个离线数据集,方便管理和遍历。

    因此真正的SqlHelper.cs应该是这样写的:

    using System.Data.SqlClient;
    using System.Data;
    
    namespace ExecuteScalar.libs
    {
        class SqlHelper
        {
            public static DataSet GetDataSet(string sql)
            {
                SqlDataAdapter sda = new SqlDataAdapter(sql,"server=.;database=WebSite;uid=sa;pwd=123456");
    
                DataSet dSet = new DataSet();
    
                sda.Fill(dSet);
    
                return dSet;
    
            }
    
        }
    }

    注意:using并不是不好,他是一个很不错的资源管理工具。但是正是由于他的自动性质,在SqlHelper中产生了麻烦,故不能在SqlHelper中使用他。其他地方,比如临时定义一个sql查询,照样可以使用。而且推荐使用!

    今早又想到了几点:

      1.在SqlHelper并不一定都不能使用using,只是大数据查询的时候不能用,因为不能有效关闭连接。而在一些只返回某个值或者某几个值的情况下(ExecuteSalar),或者ExecuteNonQuery的情况下,可以并且推荐使用using

     

  • 相关阅读:
    我要好offer之 二叉树大总结
    我要好offer之 字符串相关大总结
    楼层扔鸡蛋问题[转]
    Linux System Programming 学习笔记(十一) 时间
    Linux System Programming 学习笔记(十) 信号
    Linux System Programming 学习笔记(九) 内存管理
    Linux System Programming 学习笔记(八) 文件和目录管理
    Linux System Programming 学习笔记(七) 线程
    Linux System Programming 学习笔记(六) 进程调度
    APUE 学习笔记(十一) 网络IPC:套接字
  • 原文地址:https://www.cnblogs.com/hoosway/p/3704692.html
Copyright © 2011-2022 走看看