“错误:57014:由于用户请求而取消语句”Npgsql

gyo*_*fov 5 postgresql command npgsql dapper

我在我的应用程序中遇到了这个幻象问题,其中特定页面(在 ASP.NET MVC 应用程序上)上的每 5 个请求中就有一个抛出此错误:

Npgsql.NpgsqlException: ERROR: 57014: canceling statement due to user request
   at Npgsql.NpgsqlState.<ProcessBackendResponses>d__0.MoveNext()
   at Npgsql.ForwardsOnlyDataReader.GetNextResponseObject(Boolean cleanup)
   at Npgsql.ForwardsOnlyDataReader.GetNextRow(Boolean clearPending)
   at Npgsql.ForwardsOnlyDataReader.Read()
   at Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb)
   ...
Run Code Online (Sandbox Code Playgroud)

在 npgsql github 页面上,我发现了以下错误报告:615

它在那里说:

不管 Dapper 到底发生了什么,在取消命令时肯定存在竞争条件。部分原因是设计使然,因为 PostgreSQL:取消请求是完全“异步的”(它们通过不相关的套接字传递,而不是作为要取消的连接的一部分),并且您不能限制取消生效仅在特定命令上。换句话说,如果您想取消命令 A,则在您发送取消时,命令 B 可能已经在进行中,它将被取消。

尽管他们在 Npgsql 3.0.2 中进行“希望使取消更安全的更改”,但我当前的代码与此版本不兼容,因为这里描述了迁移的需要。

我目前的解决方法(愚蠢):我已经评论了 Dapper 中的代码,command.Cancel();问题似乎消失了。

if (reader != null)
                {
                    if (!reader.IsClosed && command != null)
                    {
                        //command.Cancel();
                    }
                    reader.Dispose();
                    reader = null;
                }
Run Code Online (Sandbox Code Playgroud)

有没有更好的解决问题的方法?其次,我在当前修复中丢失了什么(除了每次更新 Dapper 时我都必须记住更改)?

配置:NET45、Npgsql 2.2.5、Postgresql 9.3

gyo*_*fov 1

我发现为什么我的代码没有处理读取器,导致调用command.Cancel(). QueryMultiple仅当方法未refcursor读取所有内容时才会发生这种情况。

\n\n

更改代码:

\n\n
using (var multipleResults = connection.QueryMultiple("schema.getuserbysocialsecurity", new { socialSecurityNumber }))\n{\n    var client = multipleResults.Read<Client>().SingleOrDefault();\n\n    if (client != null)\n    {\n        client.Address = multipleResults.Read<Address>().Single();\n    }\n\n    return client;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

到:

\n\n
using (var multipleResults = connection.QueryMultiple("schema.getuserbysocialsecurity", new { socialSecurityNumber }))\n{\n    var client = multipleResults.Read<Client>().SingleOrDefault();\n    var address = multipleResults.Read<Address>().SingleOrDefault();\n\n    if (client != null)\n    {\n        client.Address = address;\n    }\n\n    return client;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这解决了问题,现在读者已被正确处理并且command.Cancel()不会被调用。

\n\n

希望这对其他人有帮助!

\n\n

更新

\n\n

2.2 版本的 npgsql 文档指出:

\n\n
\n

Npgsql 能够要求服务器取消正在进行的命令。为此,请调用 NpgsqlCommand\xe2\x80\x99s Cancel 方法。请注意,另一个线程必须处理该请求,因为主线程将被阻止等待命令完成。此外,主线程将因用户取消而引发异常。\n (错误代码为57014。)

\n
\n\n

我还在Dapper github 页面上发布了一个问题。

\n