SqlCommand.ExecuteNonQuery 抛出 Collection 被修改;枚举操作可能无法执行

Posted

技术标签:

【中文标题】SqlCommand.ExecuteNonQuery 抛出 Collection 被修改;枚举操作可能无法执行【英文标题】:SqlCommand.ExecuteNonQuery throws Collection was modified; enumeration operation might not execute 【发布时间】:2021-02-25 07:23:04 【问题描述】:

我有一个简单的方法来执行 SQL NON-QUERY 语句。这可以正常工作,没有任何问题,但是当有负载或 20 个线程同时调用此方法时,有时我会得到“集合已修改;枚举操作可能无法执行”。奇怪的是我在这个方法中没有任何枚举操作。

方法:

OpenConnection();
using (SqlCommand cmd = new SqlCommand(SQLQuery, Connection))

    cmd.CommandType = CommandType.Text;

    if (QueryParam.Count() > 0)
        cmd.Parameters.AddRange(QueryParam.ToArray());

    SqlParameter scopeParam = cmd.Parameters.AddWithValue("@ID", 0);
    scopeParam.Direction = ParameterDirection.Output;

    cmd.ExecuteNonQuery();
    uKey = (int)cmd.Parameters["@ID"].Value;
    cmd.Parameters.Clear();

CloseConnection()
return uKey;

例外:

Exception Found: Collection was modified; enumeration operation might not execute.

Full Exception: System.InvalidOperationException: Collection was modified; enumeration operation might not execute.
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()

顺便提一下,我正在使用 .Net 4.0 和 SQL Server。 任何帮助将不胜感激。

【问题讨论】:

OpenConnection() \ CloseConnection() - 不要这样做。在需要时创建连接,打开,完成后处理。所以在这种情况下,在创建命令之前创建它。 【参考方案1】:

单独显示的代码应该没问题;这里的症状表明另一个线程同时触及同一个Connection 实例,所以:不要那样做。连接不是线程安全的。这里的主要赠品以粗体显示:

正常工作,没有任何问题 [大概是它本身的意思],但是当有负载或20个线程同时调用此方法时,比有时我收到“集合已修改;枚举操作可能无法执行”。

仅在有时且仅在并发负载下才会发生的事情:通常是并发性。建议:确定连接范围 - 每个线程,甚至每个方法,即

using (var conn = CreateOpenConnection())
using (var cmd = new SqlCommand(SQLQuery, conn))

    // ...

【讨论】:

唯一困扰我的是异常来自 System.Data.SqlClient.SqlCommand.ExecuteNonQuery 而不是来自打开/关闭连接。 @RanjanKumar 如果你有两个线程改变了内部状态,所有的赌注都关闭 - 你处于完全未定义的领域。从字面上看,任何事情都可能发生。 (对我而言)完全可以预料到它会在内部爆炸。改变内部状态的不仅仅是打开和关闭连接

以上是关于SqlCommand.ExecuteNonQuery 抛出 Collection 被修改;枚举操作可能无法执行的主要内容,如果未能解决你的问题,请参考以下文章