获取"读取器关闭时无效尝试呼叫读取"

Tho*_*mas 1 c# sql

我有以下代码(这里有伪值以便于阅读),其中第一个连接返回大量数据(数千行).SqlDataReader逐个读取它们reader.Read(),然后打开一个新连接以使用新值更新每一行:

using (SqlConnection conn = new SqlConnection(connString))
    using (SqlCommand cmd = new SqlCommand("sp1", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@param1", param1);
        cmd.Connection.Open();
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                try
                {
                    string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
                    using (SqlConnection conn2 = new SqlConnection(connString))
                    using (SqlCommand cmd2 = new SqlCommand("sp2", conn2))
                    {
                        cmd2.CommandType = CommandType.StoredProcedure;
                        cmd2.Parameters.AddWithValue("@param1", param1);
                        cmd2.Parameters.AddWithValue("@param2", param2);
                        cmd2.Connection.Open();
                        cmd2.ExecuteNonQuery();
                    }
                }
                catch (SqlException ex)
                {
                    //something
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

但它会抛出一个错误:

[InvalidOperationException: Invalid attempt to call Read when reader is closed.]
System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) +640
System.Data.SqlClient.SqlDataReader.Read() +9
Run Code Online (Sandbox Code Playgroud)

在开发环境中它工作正常,但这里只有几百行.它会立即抛出错误,所以它不会直接看起来像某种超时,但是嘿 - 我不知道......

Sha*_*ard 5

不知道为什么会发生这种情况,但在将实时连接迭代到同一个数据库时执行查询真的是个坏主意.请记住,只要使用DataReader迭代记录,连接就会生效.

更糟糕的是打开然后快速连续数千次关闭连接.仅这一点就可以使任何数据库瘫痪.

更改逻辑,将所需的值存储在本地变量中(结构无关紧要)然后仅使用一个连接来执行所需的所有存储过程.

例如:

using (SqlConnection conn = new SqlConnection(connString))
{
    conn.Open();

    List<string[]> values = new List<string[]>();
    using (SqlCommand cmd = new SqlCommand("sp1", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@param1", param1);
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                try
                {
                    string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
                    string anotherValue = (string)reader["secondRow"];
                    values.Add(new string[] { hash, anotherValue });
                }
                catch (SqlException ex)
                {
                    //something
                }
            }
            reader.Close();
        }
    }

    if (values.Count > 0)
    {
        using (SqlCommand cmd2 = new SqlCommand("sp2", conn))
        {
            cmd2.CommandType = CommandType.StoredProcedure;
            cmd2.Parameters.AddWithValue("@param1", null);
            cmd2.Parameters.AddWithValue("@param2", null);
            values.ForEach(items =>
            {
                cmd2.Parameters["@param1"].Value = items[0];
                cmd2.Parameters["@param2"].Value = items[1];
                cmd2.ExecuteNonQuery();
            });
        }
    }
    conn.Close();
}
Run Code Online (Sandbox Code Playgroud)

一个连接,一个命令来执行所有存储过程.真的不需要更多.

  • 如果您使用连接池,"打开然后关闭数千个连接"是相当便宜的. (3认同)