ERROR: canceling statement due to user request

本文主要探讨了在使用PostgreSQL时遇到的'ERROR: canceling statement due to user request'异常。该异常通常是因为用户请求取消了正在执行的查询。可能的情况包括Http请求取消、Mybatis配置中设置的超时限制等。异常的具体表现为查询被定时器中断,导致执行循环判断时抛出异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境 : jdk1.8
架构 : Spring Boot 1.5.7+ Mybatis 3.4.3+ Druid + PostgreSQL JDBC Driver


我在使用 PostgreSQL 执行一些查询时报了一个错误,花了半天时间用来搞懂这个错误产生的原因后,决定在这里总结一下.

ERROR: canceling statement due to user request异常抛出原因.

报这个错误的主要原因是和字面上的意义一致,“由于用户的请求取消了当前查询的状态”.

Caused by: org.postgresql.util.PSQLException: ERROR: canceling statement due to user request
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2477)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2190)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:300)
	at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:428)
	at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:354)
	at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:169)
	at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:158)

可能解释的有点草率,但这里也没有办法说明的更加详细了.大致意思就是由于你代码中设置了取消执行当前查询的代码从而导致抛出这个异常.
异常的原因有可能是执行了该函数java.sql.Statement:

// java.sql.Statement:248-259
    /**
     * Cancels this <code>Statement</code> object if both the DBMS and
     * driver support aborting an SQL statement.
     * This method can be used by one thread to cancel a statement that
     * is being executed by another thread.
     *
     * @exception SQLException if a database access error occurs or
     * this method is called on a closed <code>Statement</code>
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    void cancel() throws SQLException;

PostgreSQL JDBC Driver 驱动中对该方法的实现代码是:

//org.postgresql.jdbc.PgStatement:595-606
  public void close() throws SQLException {
    // closing an already closed Statement is a no-op.
    if (isClosed) {
      return;
    }
    cleanupTimer();
    closeForNextExecution();
    isClosed = true;
  }

我目前遇到的两种问题可能会导致爆出这个错误.

  • 当用户发起 Http 请求,当该请求触发了 Sql 查询后,当还没有返回数据的时候,用户取消了该请求会导致抛出该异常;
  • 当在 Mybatis 的配置文件mybatis-config.xml中设置了defaultStatementTimeout属性(单位:秒)后当sql的查询时间超过了这个设置时间后会抛出该异常;

第一种情况不太确定.但第二种情况下驱动代码PostgreSQL JDBC Driver首先会在查询前基于defaultStatementTimeout设置的时间创建一个定时器.

//org.postgresql.jdbc:872-888
  private void startTimer() {
    /*
     * there shouldn't be any previous timer active, but better safe than sorry.
     */
    cleanupTimer();
    STATE_UPDATER.set(this, StatementCancelState.IN_QUERY);
    if (timeout == 0) {
      return;
    }
    TimerTask cancelTask = new TimerTask() {
      public void run() {
        try {
          if (!CANCEL_TIMER_UPDATER.compareAndSet(PgStatement.this, this, null)) {
            // Nothing to do here, statement has already finished and cleared
            // cancelTimerTask reference
            return;
          }
          PgStatement.this.cancel(); //**定时器中取消本次查询的代码**
        } catch (SQLException e) {
        }
      }
    };
    CANCEL_TIMER_UPDATER.set(this, cancelTask);
    connection.addTimerTask(cancelTask, timeout);//创建定时器,并且设置超时时间
  }

在执行查询时间超过定时器设置的时间后,定时器会启动并且去关闭本次sql执行.在执行完成后,等待查询的循环判断得到取消查询抛出了异常时,会将该异常包装并且抛出.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值