由于 commandTimeout 不够健壮,如何使用 Dapper 在 C# 中的 blocked/slow 数据库操作中获得可靠的超时?

How can I get a reliable timeout on a blocked/slow database operation in C# with Dapper, since commandTimeout is not robust enough?

SQL Microsoft.Data.SqlClient 中服务器的 .NET 客户端为我们提供了一个支持操作的 IDbConnection,其中许多操作具有 commandTimeout parameter。但是,我了解到 commandTimeout 应用于较低级别和 does not guarantee or even always try to timeout if the whole operation exceeds that time。 (我使用的是 Dapper 的 QueryAsync,但我认为任何数据库访问方法都会遇到同样的问题。)

那么我该如何设置才能超时或以其他方式抛出异常?我尝试了 creating a WithTimeout extension method 基于 await 延迟,但这也不能保证及时触发。我的代码现在看似随机挂起(可能是由于阻塞锁),如果它们抛出异常我可以轻松处理,但目前似乎没有办法强制数据库 QueryAsync 操作。如何使用 Dapper 在 C# 中的 blocked/slow 数据库操作中获得真正的超时?

Dapper 似乎不支持取消令牌。是否有更广泛的查询数据库的方法可以保证在特定时间内完成或出错,比如 20秒?

Is there some broader approach to querying the database that could guarantee either completion or an error in a certain time, say 20 seconds?

是的,有。有更广泛的方法来执行异步 IO,保证在指定时间内完成或出错。

在 C# 中,可以创建在给定时间跨度后取消的 CancellationTokens。大多数 async 方法接受 CancellationTokenIDbConnection.QueryAsync也不例外。

您创建了一个取消令牌源,它采用一个可选参数指定任务取消前的延迟(作为 TimeSpanint

参见示例:

try
{
  IDbConnection db = ...;
  var cts = new CancellationTokenSource(10_000);
  var cmd = new CommandDefinition(commandText: "your query", cancellationToken: cts.Token);
  await db.QueryAsync<Foo>(cmd);
  // Success.
}
catch (TaskCanceledException e)
{
// Failure due to timeout.
}