关于mysql:C#:使用CancellationToken取消MySqlCommand并给出NULLReferenceException

C# : Cancelling MySqlCommand using CancellationToken giving NULLReferenceException

我试图使用CancellationToken取消MySqlCommand。 当不请求取消时,查询成功执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task<int> ExecuteNonQueryAsync(string connectionString, string query,
       CancellationToken cancellationToken)
{
    int affectedRowsCount = 0;
    await Task.Run(() =>
    {
        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            using (MySqlCommand command = new MySqlCommand())
            {
                connection.Open();
                command.Connection = connection;
                cancellationToken.Register(() => command.Cancel());

                command.CommandText = query;
                command.CommandTimeout = 0;

                affectedRowsCount = command.ExecuteNonQuery();
                connection.Close();
             }
         }
     });

     return affectedRowsCount;
}

但是,当请求取消时,它会产生NullReferenceException。
无法弄清楚什么是NULL。

enter image description here

我正在通过以下方式调用上述方法

1
2
3
4
5
deletedRowsInLastIteration = await
    mySqlHelperService.ExecuteNonQueryAsync(
       connectionString,
       query,
       cancellationToken);

如果我尝试

1
cancellationToken.ThrowIfCancellationRequested();

在调用ExecuteNonQueryAsync()方法之前,它可以工作。 但是取消MySqlCommand无效。

这是堆栈跟踪

System.NullReferenceException HResult=0x80004003 Message=Object
reference not set to an instance of an object. Source=MySql.Data
StackTrace: at
MySql.Data.MySqlClient.MySqlConnection.CancelQuery(Int32 timeout)
at MySql.Data.MySqlClient.MySqlCommand.Cancel() at
ProjectName.Common.MySqlHelperService.<>c__DisplayClass1_1.b__1()
in
C:\\Users\\username\\source\
epos\\ProjectName\\Applications\\ProjectName.Common\\MySqlHelperService.cs:line
55 at
System.Threading.CancellationToken.ActionToActionObjShunt(Object obj)
at
System.Threading.CancellationCallbackInfo.ExecutionContextCallback(Object
obj) at
System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Threading.CancellationCallbackInfo.ExecuteCallback() at
System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments
args) at
System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean
throwOnFirstException)


您不应该使用Task.Run将同步方法转换为异步方法。 充其量,这只是在等待某些IO操作完成而浪费线程。

MySqlCommand具有ExecuteNonQueryAsync方法,该方法接受取消令牌。 MySqlConnection本身具有OpenAsync方法。 您应该将代码更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public async Task<int> ExecuteNonQueryAsync(string connectionString, string query,
       CancellationToken cancellationToken)
{
    using (MySqlConnection connection = new MySqlConnection(connectionString))
    {
        using (MySqlCommand command = new MySqlCommand(query,connection))
        {
            await connection.OpenAsync();
            command.CommandTimeout = 0;

            var affectedRowsCount = await command.ExecuteNonQuery(cancellationToken);
         }
    }

    return affectedRowsCount;
}


您如何创建取消令牌,他的价值是什么?

这也是解决方案如何使用取消令牌取消sql命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private CancellationTokenSource cts;
private async void TestSqlServerCancelSprocExecution()
{
cts = new CancellationTokenSource();
try
{
    await Task.Run(() =>
    {
        using (SqlConnection conn = new SqlConnection("connStr"))
        {
            conn.InfoMessage += conn_InfoMessage;
            conn.FireInfoMessageEventOnUserErrors = true;
            conn.Open();

            var cmd = conn.CreateCommand();
            cts.Token.Register(() => cmd.Cancel());
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText ="dbo.[CancelSprocTest]";
            cmd.ExecuteNonQuery();
        }
   });
}
catch (SqlException)
{
    // sproc was cancelled
}

}

上面的代码来自这个问题,该问题也存在相同的问题,即取消令牌不会取消sql命令。