postgresql错误:由于用户请求而取消语句

时间:2012-10-28 23:29:26

标签: java postgresql exception

在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数据库位于固态硬盘上,此错误是随机发生的,有时根本不会发生。

4 个答案:

答案 0 :(得分:14)

我们已经找出了这个问题的原因。最新JDBC驱动程序9.2-100x中的setQueryTimeout()错误实现解释了这一点。如果您手动打开/关闭连接,可能不会发生这种情况,但经常会出现连接池并且自动提交设置为 false 。在这种情况下,应该使用非零值调用setQueryTimeout()(例如,使用Spring框架@Transactional(timeout = xxx)注释)。

事实证明,只要在语句执行期间引发SQL异常,取消计时器就不会被取消并保持活动状态(这就是它的实现方式)。由于池,后面的连接没有关闭,但返回到池中。 稍后,当取消计时器触发时,它会随机取消当前与此计时器创建的连接相关联的查询。此时,这是一个完全不同的查询,解释了随机性效应。

建议的解决方法是放弃setQueryTimeout()并改为使用PostgreSQL配置(statement_timeout)。它没有提供相同水平的灵活性,但至少总是有效。

答案 1 :(得分:6)

这假设postgresql的jdbc jar文件中的竞争条件错误是造成上述错误的原因。 (这里描述的竞争条件:http://postgresql.1045698.n5.nabble.com/ERROR-canceling-query-due-to-user-request-td2077761.html

解决方法1,定期刷新与数据库的连接

一种解决方法是关闭与数据库的连接,并定期创建与数据库的新连接。每隔几千个sql语句关闭连接并重新创建它。然后由于某种原因不再抛出此错误。

解决方法2,开启日志记录

如果在设置驱动程序时打开JDBC驱动程序级别的日志记录,则在某些情况下会中和竞争条件问题:

Class.forName("org.postgresql.Driver");
org.postgresql.Driver.setLogLevel(org.postgresql.Driver.DEBUG);

解决方法3,捕获异常并重新初始化连接

您还可以尝试捕获特定异常,重新初始化连接并再次尝试查询。

解决方法4,等到postgresql jdbc jar出现错误修复

我认为问题可能与我的SSD硬盘速度有关。如果你收到这个错误,请在这里发布如何一致地重现它,开发人员非常有兴趣压缩这个错误。

答案 2 :(得分:4)

如果您在不使用交易的情况下收到此错误

用户已请求取消该声明。该声明正在完成它所要做的事情。问题是,谁要求取消此声明?

查看代码中准备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状态。

如果这是你的问题,那么在你忘记自己清理之后就不会抛出异常,它会在你在交易后未能清理很久之后的某个地方发生,这使得这是一个难以追查的例外。刷新连接(关闭它并获得一个新连接)将清除它。

答案 3 :(得分:3)

除了Eric的建议外,您还可以在以下情况下看到声明取消:

  • 以同一用户身份登录的管理员或其他连接使用pg_cancel_backend要求您的会话取消其当前声明
  • 管理员向运行语句的PostgreSQL后端发送信号
  • 管理员请求fast关闭或重新启动PostgreSQL服务器

检查可能取消长时间运行查询的cron作业或加载管理工具。