在哪里关闭SqlDataReader对象和SqlConnection对象?

时间:2017-02-24 20:13:33

标签: c# asp.net sql-server

我调用一个函数,它将一个SqlDataReader对象返回给调用语句。我很困惑应该在哪里关闭SqlDataReader对象和SqlConnection对象?在功能上还是在调用之后?

这是函数调用:

SqlDataReader dr2= RetrieveSearcher();
pid = dr2[0].ToString();

这是功能:

protected SqlDataReader RetrieveSearcher()
{
    String Q = "select price from tb3 where pid='12';
    cn = new SqlConnection("data source=.\\sqlexpress; integrated security=true; initial catalog=singh");
    cn.Open();

    cmd = new SqlCommand(Q,cn);
    dr1 = cmd.ExecuteReader();
    dr1.Read();

    return dr1;
}

2 个答案:

答案 0 :(得分:3)

  1. 始终使用参数化查询来避免SQL注入攻击并提高性能(大多数数据库服务器可以通过正确的查询重用执行计划)
  2. 永远不要让连接打开超过必要的时间!
  3. 不要共享数据库连接!创建它,使用它,销毁它。
  4. using块中包含实现IDisposable的所有内容,例如Connections,Commands,DataReaders等。这样可以确保即使发生异常也不会保留资源。
  5. 在数据库模式中使用正确的类型并读取这些类型,不要将所有内容全部转换为字符串/从字符串转换!示例price似乎应该是十进制或数字值而不是字符串,因此不要将其存储为字符串,也不要将其作为字符串读回。
  6. 从app.config或web.config按名称检索连接字符串(取决于应用程序类型),不要将字符串硬编码到您的连接或其他任何位置。
  7. 关于你的逻辑

    更改方法以返回自定义类型,例如一段数据。这确保了适当的SoS(关注点分离)。不要返回DataReader!这将抽象来自调用者的整个数据库调用,这是您应该努力的目标。

    protected SomeType RetrieveSearcherData(string pid)
    {
        const string Q = "SELECT price FROM tb3 WHERE pid = @pid";
        using(var cn=new SqlConnection())
        using(var cmd=new SqlCommand(Q,cn))
        {
            // I do not know what pid is but use tho correct type here as well and specify that type using SqlDbType
            cmd.Parameters.Add(new SqlParameter("@pid", SqlDbType.VarChar, 100) { Value = pid});
            cn.Open();
            using(var dr1= cmd.ExecuteReader())
            {
                if(dr1.Read())
                {
                   var result = dr1.GetDecimal(0);
                   // read something and return it either in raw format or in some object (use a custom type)
                }
                else
                  return null; // return something else that indicates nothing was found
            }
        }
    }
    

答案 1 :(得分:1)

  1. 您是否真的想在每次调用此功能时打开连接?让一个线程处理多个连接是获得死锁的必然方法。

  2. 如果您仍想做#1,我建议您让RetrieveSearcherList<T>或{he}返回所需的数据,只需返回DataTable和处理那个。这样,该函数可以关闭它打开的连接。

  3. 如果您仍然真的想要返回SqlDataReader,那么您需要确保可以关闭所打开的连接。 SqlDataReader不会直接公开SqlConnection,因此在您离开RetrieveSearcher方法后,无法直接关闭连接。但是,您可以这样做:

    dr1 = cmd.ExecuteReader(CommandBehavior.CloseConnection);
    

    当阅读器关闭时,这将关闭连接。那么,你可以这样做:

    using (SqlDataReader dr2 = RetrieveSearcher()) {
        pid=dr2[0].ToString();
    }
    
  4. 我当然假设您真的需要的不仅仅是一个字符串。 :)如果你真的只需要一个字符串,你只需返回字符串并调用cmd.ExecuteScalar();