简体   繁体   English

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

[英]Where to close SqlDataReader object and SqlConnection object?

I call a function which returns a SqlDataReader object to calling statement. 我调用一个函数,该函数将SqlDataReader对象返回到调用语句。 I am confused where should I close the SqlDataReader object and SqlConnection object? 我很困惑应该在哪里关闭SqlDataReader对象和SqlConnection对象? In function or after calling it? 在函数中还是在调用之后?

This is the function call: 这是函数调用:

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

This is the function: 这是功能:

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;
}
  1. Always use parameterized queries to avoid sql injection attacks and increase performance (most db servers can reuse execution plans with proper queries) 始终使用参数化查询来避免SQL注入攻击并提高性能(大多数数据库服务器可以通过适当的查询重用执行计划)
  2. Never leave a connection open any longer than necessary! 切勿将连接断开的时间超过必要!
  3. Do not share db connections! 不要共享数据库连接! Create it, use it, destroy it. 创建,使用,销毁它。
  4. Wrap everything that implements IDisposable in a using block like Connections, Commands, DataReaders, etc. This ensures no resources remain open even in the event of an exception. 将所有实现IDisposable的内容包装在using块中,例如Connections,Commands,DataReaders等。这可确保即使发生异常也不会保持打开资源的状态。
  5. Use correct types in your db schema and read those types, do not blanket-convert everything to/from string! 在您的数据库架构中使用正确的类型并读取这些类型,请勿将所有内容一一转换为字符串! Example price seems like it should really be a decimal or numeric value and not a string so do not store it as a string and do not read it back as a string. price示例似乎确实应该是十进制或数字值,而不是字符串,因此请勿将其存储为字符串,也不要将其读回为字符串。
  6. Retrieve the connection strings by name from the app.config or web.config (depending on the application type), do not hard code the strings into your connections or anywhere else. 通过名称从app.config或web.config(取决于应用程序类型)中检索连接字符串,请勿将字符串硬编码到您的连接或其他任何地方。

About your logic 关于你的逻辑

Change your method to return a custom type like a piece of data. 更改您的方法以返回自定义类型,例如一条数据。 This ensures proper SoS (Separation of Concerns). 这样可以确保适当的SoS(关注点分离)。 Do not return a DataReader! 不要返回DataReader! This will abstract the whole database call from the caller which is what you should strive for. 这将从调用者那里提取整个数据库调用,这是您应该努力的目标。

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. Do you really want to open a connection each time you call into this function? 您是否真的想在每次调用此功能时打开一个连接? Having one thread deal with multiple connections is a sure fire way to get deadlocks. 让一个线程处理多个连接是获得死锁的肯定方法。

  2. If you still want to do #1, I'd recommend having your RetrieveSearcher return the data it needs in a List<T> or heck, just return a DataTable and deal with that. 如果您仍然想做#1,我建议您让RetrieveSearcherList<T>或heck的形式返回所需的DataTable ,只需返回一个DataTable并进行处理即可。 That way the function can close the connection that it opened. 这样,函数可以关闭其打开的连接。

  3. If you still REALLY want to return a SqlDataReader then you need to make sure that you can close the connection that you opened. 如果您仍然真的想返回SqlDataReader则需要确保可以关闭打开的连接。 SqlDataReader doesn't expose a SqlConnection directly, so you can't directly close the connection after you leave the RetrieveSearcher method. SqlDataReader不会直接公开SqlConnection ,因此,在离开RetrieveSearcher方法后, 无法直接关闭连接。 However, you can do this: 但是,您可以这样做:

     dr1 = cmd.ExecuteReader(CommandBehavior.CloseConnection); 

    That will close the connection when the reader is closed. 当阅读器关闭时,这将关闭连接。 So, then you can do: 因此,您可以执行以下操作:

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

I'm assuming of course that you REALLY need more than just one string. 我当然假设您确实需要多个字符串。 :) If you REALLY only need one string you just be returning the string and calling cmd.ExecuteScalar(); :)如果您只需要一个字符串,则只需返回该字符串并调用cmd.ExecuteScalar();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM