重用SqlConnection的最佳实践

Hik*_*ari 11 .net c# connection-pooling idisposable sqlconnection

我来自Java经验,我试图从C#开始.我已经阅读了SqlConnection SqlCommand SqlDataReader IDisposable,我可以理解连接到数据库的最佳做法是包装SqlConnection,SqlCommandSqlDataReader在他们自己的using块中.

但在Java中,我们使用将连接封装到工厂方法中,只创建一次,并将其重用于所有查询,甚至是多线程查询.仅为每个查询创建语句和结果集,并尽快关闭.

是不是SqlConnection为每个查询创建一个新的有点矫枉过正?不能重复使用吗?

Phi*_*ipH 30

创建类的新实例SqlConnection不会创建到SQL Server的新网络连接,而是租用现有连接(或创建新连接)..NET为您处理物理连接池.

完成连接后(通过它可以发送多个查询)Close()Dispose()(或using{}最好使用块).

缓存SqlConnection类的实例没有必要,也没有好的做法.

  • @Harry - 遗憾的是,MySql库编写者没有遵循预先存在的SqlClient方法,但很高兴你指出了它. (5认同)
  • 对于MS SQL是真的.经过MySQL测试 - 重用连接可以获得可观的性能提升.但是 - 需要自己的"连接池"才能使操作成为线程安全的.从其他线程访问连接对象会导致异常.所以对于MySQL,我重用了同一个`ManagedThreadId`的连接. (4认同)

VMA*_*Atm 6

MS SQL服务器管理它自己的连接池中的连接,并且它们实际上没有被处理掉.但它们已关闭,因此您可以最小化网络流量并释放与服务器的可用连接.

此外,您应该注意,如果您使用的是Linq-To-SQL,数据上下文在释放之前不会释放连接,因此我建议您只使用已经正常工作的代码而不要尝试自己优化它.

  • 我认为.Net客户端而不是服务器正在管理这些连接并根据需要汇集它们. (6认同)
  • "而且它们实际上并没有被处理掉.但它们已被关闭" - 反过来; 他们被处置(如果你正确使用`using`等),很可能是垃圾收集(非确定性等),但*底层*非托管连接仍然*打开* (5认同)

Rya*_*ann 5

正如 VMAtm 所说,.net 自行池化连接,因此完全可以重新创建它们。因此,我通常会像这样为整个过程编写一个包装器。

        public static void RunWithOpenSqlConnection(string connectionString, Action<SqlConnection> connectionCallBack)
    {
        SqlConnection conn = null;
        try
        {
            conn = new SqlConnection(connectionString);
            connectionCallBack(conn);
        }
        catch (Exception ex)
        {
            //Log Error Here
        }
        finally
        {
            if (conn != null)
                conn.Dispose(); //will close the connection
        }
    }

    public static void ExecuteSqlDataReader(string connectionString, string sqlCommand, Action<SqlDataReader> readerCallBack)
    {
        RunWithOpenSqlConnection(connectionString, delegate(SqlConnection conn)
        {
            SqlCommand cmd = null;
            SqlDataReader reader = null;
            try
            {
                cmd = new SqlCommand(sqlCommand, conn);
                reader = cmd.ExecuteReader();
                readerCallBack(reader);
            }
            catch (Exception ex)
            {
                //Log Error Here
            }
            finally
            {
                if (reader != null)
                    reader.Dispose();
                if (cmd != null)
                    cmd.Dispose();
            }
        });
    }

//Example calling these
            ExecuteSqlDataReader(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString, "Select EmployeeID FROM Employees;", delegate(SqlDataReader reader)
        {
            List<string> employeeIds = new List<string>();
            if (reader.HasRows)
            {
                while(reader.Read())
                {
                    employeeIds.Add((string)reader[0]);
                }
            }
        });
Run Code Online (Sandbox Code Playgroud)

  • @transformer 自从我写这篇文章以来,我们已经修改了很多。我会尽快记住发布一个更好的例子。基本上,尽管我们已经与类似“GetListFromProc&lt;MyThing&gt;(storedProcName, getItemFromReader); 之类的东西进行了交战,它返回一个 MyThing 列表,getItemFromReader 是一个函数,它传递了 SqlDataReader 行,您在其中实例化 MyThing 并返回它。 (3认同)