Postgresql error: отмена заявления из-за запроса пользователя

Что вызывает эту ошибку в 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

Clue: моя база данных postgresql находится на твердотельном жестком диске, и эта ошибка происходит случайно, а иногда и вовсе.

Ответ 1

Мы выяснили причину этой проблемы. Это объясняется ошибкой реализации setQueryTimeout() в последних драйверах JDBC 9.2-100x. Это может не произойти, если вы открываете/закрываете соединение вручную, но очень часто происходит с пулом соединений на месте, а autocommit - false. В этом случае setQueryTimeout() следует вызывать с ненулевым значением (например, используя аннотацию Spring framework @Transactional (timeout = xxx)).

Оказывается, всякий раз, когда исключение SQL возникает во время выполнения инструкции, таймер отмены не отменяется и остается в живых (как он реализован). Из-за объединения, соединение позади не закрыто, но возвращается в пул. Позже, когда таймер отмены срабатывает, он случайным образом отменяет запрос, связанный в настоящее время с соединением, с которым был создан этот таймер. В настоящий момент это совершенно другой запрос, который объясняет эффект случайности.

Предлагаемое обходное решение - отказаться от setQueryTimeout() и вместо этого использовать конфигурацию PostgreSQL (statement_timeout). Он не обеспечивает такой же уровень гибкости, но, по крайней мере, всегда работает.

Ответ 2

Если вы получаете эту ошибку без использования транзакций

Пользователь попросил отменить выражение. Заявление делает именно то, что ему говорят. Вопрос в том, кто просил это выражение быть отменено?

Посмотрите на каждую строку вашего кода, которая подготавливает SQL для выполнения. У вас может быть какой-то метод, применимый к утверждению, которое отменяет утверждение при некоторых обстоятельствах, например:

statement = conn.createStatement();
conn.setAutoCommit(true);
statement.setQueryTimeout(25);
my_insert_statement.setString(1, "moobars");

my_insert_statement.executeUpdate();
statement.close();

В моем случае, что случилось, я установил тайм-аут запроса на 25 секунд, и когда вставка заняла больше времени. Он передал исключение "отмена из-за исключения пользователя".

Если вы получаете эту ошибку при использовании транзакций:

Если вы получите это исключение, дважды проверьте весь свой код, который выполняет транзакции SQL.

Если у вас есть запрос, который находится в транзакции, и вы забываете совершить транзакцию, а затем используете это соединение, чтобы делать что-то еще, где вы работаете, как если бы вы не находились в транзакции, может быть поведение undefined, которое производит это исключение.

Убедитесь, что весь код, выполняющий транзакцию, очищается после себя. Убедитесь, что транзакция начинается, выполняются работы, выполняется больше работы, а транзакция откатывается или фиксируется, а затем убедитесь, что соединение осталось в состоянии autocommit=true.

Если это ваша проблема, тогда исключение не бросается туда, где вы забыли очистить себя, это происходит где-то долго после того, как вы не смогли очистить после транзакции, сделав это неуловимым исключением для отслеживания. Обновление соединения (закрытие и получение нового) очистит его.

Ответ 3

Это предполагает, что ошибка ошибки гонки в jarb jar файле для postgresql отвечает за указанную выше ошибку. (состояние гонки описано здесь: 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, дождитесь появления jQuery jgbc jgbc с исправлением ошибки

Я думаю, что проблема может быть связана со скоростью моего SSD-накопителя. Если вы получите эту ошибку, сообщите, как ее последовательно воспроизводить здесь, есть разработчики, очень заинтересованные в раздавливании этой ошибки.

Ответ 4

В дополнение к предложениям Эрика вы можете видеть, что оператор отменяет, когда:

  • Администратор или другое соединение, зарегистрированное как один и тот же пользователь, использует pg_cancel_backend, чтобы попросить ваш сеанс отменить его текущий оператор
  • Администратор отправляет сигнал на бэкэнд PostgreSQL, который запускает ваш оператор
  • Администратор запрашивает fast выключение или перезапуск сервера PostgreSQL

Проверьте задания cron или инструменты управления загрузкой, которые могут отменить длительные запросы.