32

postgresqlでこのエラーが発生する原因は何ですか?

org.postgresql.util.PSQLException: ERROR: canceling statement due to user request

私のソフトウェアバージョン:

PostgreSQL9.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

4 に答える 4

29

この問題の原因を特定しました。これは、最新のJDBCドライバー9.2-100xでのsetQueryTimeout()のバグのある実装によって説明されています。手動で接続を開いたり閉じたりした場合は発生しない可能性がありますが、接続プールが設定されていて自動コミットがfalseに設定されている場合によく発生します。この場合、setQueryTimeout()はゼロ以外の値で呼び出す必要があります(例として、Springフレームワークの@Transactional(timeout = xxx)アノテーションを使用します)。

ステートメントの実行中にSQL例外が発生するたびに、キャンセルタイマーはキャンセルされず、存続します(これが実装方法です)。プールのため、背後の接続は閉じられませんが、プールに戻されます。その後、キャンセルタイマーがトリガーされると、このタイマーが作成された接続に現在関連付けられているクエリがランダムにキャンセルされます。現時点では、ランダム性の影響を説明するまったく異なるクエリです。

推奨される回避策は、setQueryTimeout()をあきらめて、代わりにPostgreSQL構成(statement_timeout)を使用することです。同じレベルの柔軟性はありませんが、少なくとも常に機能します。

于 2013-01-04T14:02:45.087 に答える
7

これは、postgresqlのjdbcjarファイルの競合状態のバグが上記のエラーの原因であると想定しています。

回避策1、データベースへの接続を定期的に更新します

回避策の1つは、データベースへの接続を閉じて、データベースへの新しい接続を定期的に作成することです。数千のSQLステートメントごとに、接続を閉じて再作成します。その後、何らかの理由でこのエラーはスローされなくなりました。

回避策2、ログをオンにする

ドライバーを設定するときにJDBCドライバーレベルでログをオンにすると、状況によっては競合状態の問題が解消されます。

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

回避策3、例外をキャッチして接続を再初期化します

また、特定の例外をキャッチし、接続を再初期化して、クエリを再試行することもできます。

回避策4、postgresqljdbcjarがバグ修正で出力されるまで待ちます

この問題は、SSDハードドライブの速度に関連している可能性があると思います。このエラーが発生した場合は、一貫して再現する方法をここに投稿してください。このバグを潰すことに非常に興味を持っている開発者がいます。

于 2012-11-12T17:34:37.500 に答える
6

トランザクションを使用せずにこのエラーが発生した場合

ユーザーがステートメントのキャンセルを要求しました。ステートメントは、指示されたとおりに実行しています。問題は、誰がこの声明のキャンセルを要求したのかということです。

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状態のままであることを確認してください。

これが問題である場合、自分でクリーンアップするのを忘れた場所で例外がスローされることはありません。トランザクション後にクリーンアップに失敗した後のどこかで発生するため、追跡するのが難しい例外になります。接続を更新する(接続を閉じて新しい接続を取得する)と、接続がクリアされます。

于 2012-10-28T23:29:25.893 に答える
4

エリックの提案に加えて、次の場合にステートメントがキャンセルされることがわかります。

  • 同じユーザーがpg_cancel_backend現在のステートメントをキャンセルするようにセッションに要求するために使用するときにログインした管理者または別の接続
  • 管理者は、ステートメントを実行しているPostgreSQLバックエンドにシグナルを送信します
  • fast管理者がPostgreSQLサーバーのシャットダウンまたは再起動を要求します

長時間実行されるクエリをキャンセルする可能性のあるcronジョブまたは負荷管理ツールを確認します。

于 2012-10-29T01:05:33.037 に答える