postgresqlエラー:ユーザー要求によるステートメントのキャンセル
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データベースはソリッドステートハードドライブにあり、このエラーはランダムに発生し、場合によってはまったく発生しません。
この問題の原因を突き止めました。これは、最新のJDBCドライバー9.2-100xでのsetQueryTimeout()のバグの多い実装によって説明されています。接続を手動で開いたり閉じたりした場合は発生しない可能性がありますが、接続プーリングが設定されていてautocommitがfalseに設定されていると非常に頻繁に発生します。この場合、(例として、Springフレームワークの@Transactional(timeout = xxx)アノテーションを使用して)ゼロ以外の値でsetQueryTimeout()を呼び出す必要があります。
ステートメントの実行中にSQL例外が発生した場合はいつでも、キャンセルタイマーはキャンセルされておらず、生きたままです(そのように実装されています)。プールのため、背後の接続は閉じられずにプールに戻されます。その後、キャンセルタイマーがトリガーされると、このタイマーが作成された接続に現在関連付けられているクエリがランダムにキャンセルされます。現時点では、ランダム効果を説明するのはまったく別のクエリです。
推奨される回避策は、setQueryTimeout()をあきらめて、代わりにPostgreSQL構成を使用することです(statement_timeout)。同じレベルの柔軟性はありませんが、少なくとも常に機能します。
これは、postgresqlのjdbc jarファイルの競合状態のバグが上記のエラーの原因であると想定しています。 (ここで説明する競合状態: http://postgresql.1045698.n5.nabble.com/ERROR-canceling-query-due-to-user-request-td2077761.html )
回避策1、データベースへの接続を定期的に更新します
1つの回避策は、データベースへの接続を閉じ、データベースへの新しい接続を定期的に作成することです。数千のSQLステートメントごとに、接続を閉じて再作成します。その後、何らかの理由でこのエラーがスローされなくなりました。
回避策2、ロギングをオンにします
ドライバーを設定するときにJDBCドライバーレベルでロギングをオンにすると、状況によっては競合状態の問題が解消されます。
Class.forName("org.postgresql.Driver");
org.postgresql.Driver.setLogLevel(org.postgresql.Driver.DEBUG);
回避策3、例外をキャッチし、接続を再初期化します
特定の例外をキャッチし、接続を再初期化して、クエリを再試行することもできます。
回避策4、postgresql jdbc jarがバグ修正で出てくるまで待ちます
SSDハードドライブの速度に問題がある可能性があります。このエラーが発生した場合は、一貫して再現する方法をここに投稿してください。開発者はこのバグをつぶすことに非常に関心があります。
トランザクションを使用せずにこのエラーが発生した場合
ユーザーがステートメントのキャンセルを要求しました。このステートメントは、指示されたとおりのことを実行しています。問題は、この声明のキャンセルを要求したのは誰ですか?
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
状態。
これがあなたの問題である場合、自分の後にクリーンアップするのを忘れた場所で例外はスローされません。トランザクション後にクリーンアップに失敗した後、どこかで発生するため、これを追跡するのはとらえどころのない例外になります。接続を更新する(接続を閉じて新しい接続を取得する)と、接続がクリアされます。
エリックの提案に加えて、次の場合にステートメントのキャンセルを確認できます。
- 同じユーザーとしてログインしている管理者または別の接続が
pg_cancel_backend
現在のステートメントをキャンセルするようにセッションに要求する - 管理者がステートメントを実行しているPostgreSQLバックエンドにシグナルを送信します
- 管理者は、PostgreSQLサーバーの
fast
シャットダウンまたは再起動を要求します
長時間実行されているクエリをキャンセルしている可能性があるcronジョブまたは負荷管理ツールを確認します。