postgresql 错误:由于用户请求而取消语句
Posted
技术标签:
【中文标题】postgresql 错误:由于用户请求而取消语句【英文标题】:postgresql error: canceling statement due to user request 【发布时间】:2012-10-18 07:45:23 【问题描述】:postgresql 中出现此错误的原因是什么?
org.postgresql.util.PSQLException: ERROR: canceling statement due to user request
我的软件版本:
PostgreSQL 9.1.6 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2), 64-bit".
我的 postgresql 驱动是:postgresql-9.2-1000.jdbc4.jar
使用java版本:Java 1.7
提示:我的 postgresql 数据库位于固态硬盘上,此错误是随机发生的,有时根本不会发生。
【问题讨论】:
在 PostgreSQL 9.2.1 上遇到同样的问题(PostgreSQL 9.2.1 on x86_64-unknown-linux-gnu,由 gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52) 编译), 64 位),具有相同的 JDK 和 postgresql-9.2-1001.jdbc4.jar 驱动程序。数据库在旋转驱动器上,语句取消随机发生,应用程序不取消任何 SQL 语句,语句超时设置为 0(无限期)。尚未确定原因/解决方案。 仅供参考:postgresql-42.2.2
JDBC 驱动程序仍然是实际的
我可能在 postgresql-42.2.9 JDBC 驱动程序上遇到过这个问题(但不确定,可能是其他问题)。我的很奇怪,当我删除了一个按日期字段过滤的 where 和子句时,它就消失了。
更新到 postgresql-42.2.18 JDBC 驱动程序修复了这个问题,我在 AWS EMR 5.29 上使用 spark 2.4.4 scala 2.11 作业得到它。
【参考方案1】:
如果您在不使用事务的情况下收到此错误
用户已请求取消该语句。该声明正在做它被告知要做的事情。问题是,谁要求取消这个声明?
查看代码中准备执行 SQL 的每一行。你可以有一些方法适用于在某些情况下取消该语句的语句,如下所示:
statement = conn.createStatement();
conn.setAutoCommit(true);
statement.setQueryTimeout(25);
my_insert_statement.setString(1, "moobars");
my_insert_statement.executeUpdate();
statement.close();
在我的情况下,发生的事情是我将查询超时设置为 25 秒,而插入时间比这更长。它通过了“由于用户请求而取消声明”异常。
如果您在使用事务时遇到此错误:
如果您收到此异常,请仔细检查执行 SQL 事务的所有代码。
如果您有一个事务中的查询并且您忘记提交,然后您使用该连接执行其他操作,就像您不在事务中一样,则可能存在未定义的行为会产生此异常.
确保执行事务的所有代码都在自行清理。确保事务开始,工作完成,完成更多工作,事务回滚或提交,然后确保连接保持在autocommit=true
状态。
如果这是您的问题,那么在您自己忘记清理的地方不会抛出异常,它会在您未能在事务后清理很久之后发生,这使得它成为难以追踪的异常。刷新连接(关闭它并获取一个新连接)将清除它。
【讨论】:
【参考方案2】:除了 Eric 的建议之外,您还可以看到语句在以下情况下取消:
以同一用户身份登录的管理员或其他连接使用pg_cancel_backend
要求您的会话取消其当前语句
管理员向运行您的语句的 PostgreSQL 后端发送信号
管理员请求 fast
关闭或重新启动 PostgreSQL 服务器
检查可能取消长时间运行的查询的 cron 作业或负载管理工具。
【讨论】:
【参考方案3】:这假设 postgresql 的 jdbc jar 文件中的竞争条件错误是造成上述错误的原因。
解决方法 1,定期刷新与数据库的连接
一种解决方法是关闭与数据库的连接并定期创建与数据库的新连接。在每几千条 sql 语句之后,只需关闭连接并重新创建它。然后由于某种原因不再抛出此错误。
解决方法 2,打开日志记录
如果您在设置驱动程序时在 JDBC 驱动程序级别打开日志记录,那么在某些情况下竞争条件问题会被抵消:
Class.forName("org.postgresql.Driver");
org.postgresql.Driver.setLogLevel(org.postgresql.Driver.DEBUG);
解决方法 3,捕获异常并重新初始化连接
您也可以尝试捕获特定异常,重新初始化连接并再次尝试查询。
解决方法 4,等到 postgresql jdbc jar 出现错误修复
我认为问题可能与我的 SSD 硬盘驱动器的速度有关。如果您收到此错误,请在此处发布如何始终如一地重现它,开发人员非常有兴趣消除此错误。
【讨论】:
链接给出 404【参考方案4】:我们已经找出了这个问题的原因。这是由最新的 JDBC 驱动程序 9.2-100x 中的 setQueryTimeout() 的错误实现来解释的。如果您手动打开/关闭连接可能不会发生这种情况,但通常会在连接池到位且 autocommit 设置为 false 时发生。在这种情况下,应该使用非零值调用 setQueryTimeout()(例如,使用 Spring 框架 @Transactional(timeout = xxx) 注解)。
事实证明,无论何时在语句执行期间引发 SQL 异常,取消计时器都没有被取消并保持活动状态(这就是它的实现方式)。由于池化,后面的连接没有关闭,而是返回到池中。 稍后,当取消计时器触发时,它会随机取消当前与创建此计时器的连接关联的查询。目前,这是一个完全不同的查询来解释随机性效应。
建议的解决方法是放弃 setQueryTimeout() 并改用 PostgreSQL 配置 (statement_timeout)。它没有提供相同级别的灵活性,但至少总是有效。
【讨论】:
一个可能相关的问题已在 v. 9.4.1205 中修复,想知道它是否相关:github.com/pgjdbc/pgjdbc/issues/412以上是关于postgresql 错误:由于用户请求而取消语句的主要内容,如果未能解决你的问题,请参考以下文章
用户取消应用请求后,Laravel 5 Socialite Facebook 登录错误处理回调