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 или инструменты управления загрузкой, которые могут отменить длительные запросы.