PSQLException: текущая транзакция отменяется, команды игнорируются до конца блока транзакции

152

Я вижу следующую (усеченную) стековую трассировку в файле server.log JBoss 7.1.1 Final:

Caused by: org.postgresql.util.PSQLException: 
ERROR: current transaction is aborted, commands ignored until end of 
transaction block

at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:302)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_23]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_23]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_23]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_23]
at org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection$StatementHandler.invoke(AbstractJdbc23PooledConnection.java:455)
at $Proxy49.executeUpdate(Unknown Source)   at org.jboss.jca.adapters.jdbc.WrappedStatement.executeUpdate(WrappedStatement.java:371)
at org.infinispan.loaders.jdbc.TableManipulation.executeUpdateSql(TableManipulation.java:154) [infinispan-cachestore-jdbc-5.1.2.FINAL.jar:5.1.2.FINAL]
... 154 more

Проверка файла журнала Postgres показывает следующие утверждения:

STATEMENT:  SELECT count(*) FROM ISPN_MIXED_BINARY_TABLE_configCache
ERROR:  current transaction is aborted, commands ignored until end of transaction block
STATEMENT:  CREATE TABLE ISPN_MIXED_BINARY_TABLE_configCache(ID_COLUMN VARCHAR(255) NOT NULL, DATA_COLUMN BYTEA, TIMESTAMP_COLUMN BIGINT, PRIMARY KEY (ID_COLUMN))
ERROR:  relation "ispn_mixed_binary_table_configcache" does not exist at character 22

Я использую Infinispan, поставляемый с JBoss 7.1.1 Final, то есть 5.1.2.Final.

Вот что я думаю происходит:

  • Infinispan пытается запустить SELECT count(*)...оператор, чтобы увидеть, есть ли какие-либо записи в ISPN_MIXED_BINARY_TABLE_configCache;
  • Postgres почему-то не нравится это утверждение.
  • Infinispan игнорирует это и продвигает CREATE TABLEзаявление.
  • Postgres barfs, потому что он все еще думает, что это та же транзакция, которую Infinispan не удалось откатить, и эта транзакция формируется из первого SELECT count(*)...оператора.

Что означает эта ошибка и есть идеи, как ее обойти?

Jimidy
источник
Просто если вы пришли сюда, как я в поисках выше PSQLException: current transaction is aborted...( 25P02) и, возможно, также JPAили Hibernate. Наконец это было связано с нашим (хороший!) Logback использования подается с toString()-overloaded объект DAO , который вызвал ошибку и был приятно проглоченной (но accidentially незамеченной мною): log.info( "bla bla: {}", obj )производится bla bla: [FAILED toString()]. изменив его, log.info( "bla bla: {}", String.valueOf( obj )сделав его нулевым, но не проглотив его, и, таким образом, оставив транзакцию открытой при сбое несвязанного запроса.
Андреас Дитрих
Я получаю такую ​​же ошибку. Я должен был освободить соединение до sql. Мой код был connection.commit ()
MD. Ariful Ахсан

Ответы:

203

Я получил эту ошибку, используя Java и postgresql, делая вставку в таблицу. Я проиллюстрирую, как вы можете воспроизвести эту ошибку:

org.postgresql.util.PSQLException: ERROR: 
current transaction is aborted, commands ignored until end of transaction block

Резюме:

Причина, по которой вы получаете эту ошибку, заключается в том, что вы ввели транзакцию и один из ваших SQL-запросов не прошел, и вы сожрали этот сбой и проигнорировали его. Но этого было недостаточно, ТОГДА вы использовали то же самое соединение, используя ОДНУ ЖЕ СДЕЛКУ, чтобы выполнить другой запрос. Исключение возникает при втором правильно сформированном запросе, потому что вы используете прерванную транзакцию для выполнения дополнительной работы. Postgresql по умолчанию останавливает вас от этого.

Я использую: 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

Вот инструкция создания таблицы, иллюстрирующая исключение:

CREATE TABLE moobar
(
    myval   INT
);

Java-программа вызывает ошибку:

public void postgresql_insert()
{
    try  
    {
        connection.setAutoCommit(false);  //start of transaction.

        Statement statement = connection.createStatement();

        System.out.println("start doing statement.execute");

        statement.execute(
                "insert into moobar values(" +
                "'this sql statement fails, and it " +
                "is gobbled up by the catch, okfine'); ");

        //The above line throws an exception because we try to cram
        //A string into an Int.  I Expect this, what happens is we gobble 
        //the Exception and ignore it like nothing is wrong.
        //But remember, we are in a TRANSACTION!  so keep reading.

        System.out.println("statement.execute done");

        statement.close();

    }
    catch (SQLException sqle)
    {
        System.out.println("keep on truckin, keep using " +
                "the last connection because what could go wrong?");
    }

    try{
        Statement statement = connection.createStatement();

        statement.executeQuery("select * from moobar");

        //This SQL is correctly formed, yet it throws the 
        //'transaction is aborted' SQL Exception, why?  Because:
        //A.  you were in a transaction.
        //B.  You ran a sql statement that failed.
        //C.  You didn't do a rollback or commit on the affected connection.

    }
    catch (SQLException sqle)
    {
        sqle.printStackTrace();
    }   

}

Приведенный выше код производит этот вывод для меня:

start doing statement.execute

keep on truckin, keep using the last connection because what could go wrong?

org.postgresql.util.PSQLException: 
  ERROR: current transaction is aborted, commands ignored until 
  end of transaction block

обходные:

У вас есть несколько вариантов:

  1. Самое простое решение: не участвовать в сделке. Установите connection.setAutoCommit(false);для connection.setAutoCommit(true);. Это работает, потому что тогда неудачный SQL просто игнорируется как неудачный SQL-оператор. Вы можете проваливать SQL-запросы все, что хотите, и postgresql не остановит вас.

  2. Оставайтесь в транзакции, но когда вы обнаружите, что первый sql не удалось, откат / перезапуск или фиксация / перезапуск транзакции. Затем вы можете продолжать выполнять столько SQL-запросов для этого подключения к базе данных, сколько хотите.

  3. Не перехватывайте и не игнорируйте исключение, которое выдается при сбое оператора SQL. Затем программа остановится на некорректном запросе.

  4. Вместо этого получите Oracle, Oracle не выдает исключение, когда вы не выполняете запрос на соединение в транзакции и продолжаете использовать это соединение.

В защите решения PostGreSQL, чтобы сделать что - то так ... Oracle был сделать вас мягким в середине позволяя вам делать тупые вещи и вид его.

Эрик Лещинский
источник
10
Lol @ Вариант 4 ... Я довольно много занимался разработкой в ​​Oracle, и недавно начал использовать Postgres ... Это действительно раздражает, что Postgres делает это, и теперь мы должны действительно переписать большую часть нашей программы, которую мы портируют с Oracle на Postgres. Почему нет варианта, подобного первому, чтобы он вел себя как Oracle, но без автоматической фиксации ?
ADTC
2
После нескольких испытаний выяснилось, что вариант 2 наиболее близок к поведению Oracle. Если вам необходимо оформить несколько обновлений, и один отказ не должен остановить последующие обновления, просто позвоните rollback()на Connectionкогда SQLExceptionпоймана. [ Во всяком случае, я понял, что это соответствует философии PostgreSQL, заставляющей пользователя делать все ясно, в то время как Oracle
придерживается
2
Вариант 2 содержит невозможную ветку or commit/restart the transaction. Как я вижу, нет никакого способа сделать коммит после исключения. Когда я пытаюсь зафиксировать - PostgreSQL делаетrollback
turbanoff
1
Я могу подтвердить проблему, поднятую @turbanoff. Это также может быть воспроизведено непосредственно с psql. (1) начать транзакцию, (2) выдать несколько допустимых операторов, (3) выдать недопустимый оператор, (4) commit -> psql выполнит откат вместо фиксации.
Alphaaa
1
postgresql.org/message-id/op.ur57x9ue33x80h%40insanity.lain.pl интересное обсуждение этой темы. Если эта проблема вызвана нарушением ограничения, разработчики PostgreSQL рекомендуют заранее проверять наличие конфликта (запрос перед обновлением / вставкой) или использовать savepointsдля отката до точки перед обновлением / вставкой. См. Stackoverflow.com/a/28640557/14731 для примера кода.
Гили
27

Проверьте вывод перед оператором, который вызвал current transaction is aborted. Обычно это означает, что база данных вызвала исключение, которое ваш код проигнорировал, и теперь ожидает, что следующие запросы вернут некоторые данные.

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

В таких случаях вы должны перехватывать все исключения и транзакции отката.

Вот похожая проблема.

vyegorov
источник
Это здорово, за исключением того, что в данном случае это будет Infinispan, сторонняя библиотека, которая будет общаться с Postgres, а не мой код.
Джимиди
Что ж, ситуация все та же - транзакцию нужно откатить. Возможно, проверьте, есть ли более новая версия библиотеки, которую вы используете, или поднимите проблему в их баг-трекере. Если вы точно найдете SQLпричину проблемы, у вас будет поле для устранения проблемы с помощью расширяемости PostgreSQL.
выегоров
Похоже, вы подтвердили мои подозрения - сейчас я собираюсь посмотреть на источник Infinispan 5.1.2.
Джимиди
Чтобы быть справедливым, в классе TableManipulation есть попытка-ловушка при попытке запустить select count (*) .... Возможно, драйвер Postgres не выдает одно из ожидаемых исключений. Я подключу отладчик к JBoss, чтобы попытаться узнать больше.
Джимиди
Рассматриваемый код Infinispan был предложен в этой ошибке: questions.jboss.org/browse/… Я прикрепил к нему отладчик, работающий на живом экземпляре JBoss 7.1.1, и Postgres выбрасывает исключения в нужных местах. Возможно, именно операторы JdbcUtil.safeClose () не выполняют свою работу. Я подниму это с Infinispan.
Джимиди
13

Я думаю, что лучшим решением является использование java.sql.Savepoint.

Перед выполнением запроса, который может выдать SQLException, используйте метод Connection.setSavepoint (), и, если будет сгенерировано исключение, вы только откатитесь до этой точки сохранения, а не откатите всю транзакцию.

Пример кода:

Connection conn = null;
Savepoint savepoint = null;
try {
    conn = getConnection();
    savepoint = conn.setSavepoint();
    //execute some query
} catch(SQLException e) {
    if(conn != null && savepoint != null) {
        conn.rollback(savepoint);
    }
} finally {
   if(conn != null) {
      try {
          conn.close();
      } catch(SQLException e) {}

   }
}
Михал Орлинский
источник
Я случайно понизил как-то, только заметил. Не был намеренным, я не могу отменить, если ответ не отредактирован.
Цербер
Путь сохранения - это актуальное решение. У меня работает также в среде PHP, Doctrine2 и Postgres (9.5). Спасибо
helvete
6

Над драйвером postgresql была проделана определенная работа, связанная с этим поведением:
см. Https://github.com/pgjdbc/pgjdbc/pull/477.

Теперь это возможно, установив

автосохранение = всегда
в соединении (см. https://jdbc.postgresql.org/documentation/head/connect.html ), чтобы избежать синдрома «текущая транзакция прервана».
Накладные расходы из-за обработки точки сохранения при выполнении оператора остаются очень низкими (подробности см. По ссылке выше).

Тьерри Массон
источник
5

В Ruby on Rails PG я создал миграцию, перенес свою БД, но забыл перезапустить сервер разработки. Я перезапустил свой сервер, и он работал.

thedanotto
источник
Это был и мой случай. Думал, что это должно быть что-то глупое, потому что я действительно не пытался делать что-то такое сложное.
Tashows
4

Причина этой ошибки заключается в том, что существуют другие базы данных, прежде чем неправильная операция привела к невозможности выполнения текущей операции базы данных (я использую перевод Google, чтобы перевести мой китайский на английский)

管 浩浩
источник
2

Эта проблема была исправлена ​​в Infinispan 5.1.5.CR1: ISPN-2023

Дэн Бериндей
источник
2

Вам нужно откатиться. Драйвер JDBC Postgres довольно плохой. Но если вы хотите сохранить транзакцию и просто откатить эту ошибку, вы можете использовать точки сохранения:

try {
_stmt = connection.createStatement();
_savePoint = connection.setSavepoint("sp01");
_result = _stmt.executeUpdate(sentence) > 0;
} catch (Exception e){
 if (_savePoint!=null){
 connection.rollback(_savePoint);
}
}

Узнайте больше здесь:

http://www.postgresql.org/docs/8.1/static/sql-savepoint.html

Мариано Л
источник
2

У меня была такая же проблема, но потом я понял, что в базе данных есть таблица с таким же именем. После удаления я смог импортировать файл.

S.Perera
источник
Это была моя проблема, таблицы для меня были в двух разных схемах.
томат
0

Это очень странное поведение PostgreSQL, оно даже не «соответствует философии PostgreSQL по принуждению пользователя делать все явным» - исключение было явно обнаружено и проигнорировано. Так что даже эта защита не держится. Oracle в этом случае ведет себя гораздо удобнее и (как по мне) правильно - это оставляет выбор разработчику.

AL0
источник
0

Это может произойти, если у вас недостаточно места на диске.

gregb
источник
Я понимаю, что это не самая распространенная причина, но это был случай на сервере, который меня попросили устранить. Поэтому я думаю, что это должно быть указано в качестве потенциальной причины.
Грегб
0

Я просто сталкиваюсь с той же ошибкой. Мне удалось выяснить первопричину, включив log_statement и log_min_error_statement в моем локальном PostgreSQL.

Я сослался на это

virtualpathum
источник
0

Я использую JDBI с Postgres и столкнулся с той же проблемой, то есть после нарушения какого-либо ограничения из оператора предыдущей транзакции последующие операторы не будут выполнены (но через некоторое время, скажем, 20-30 секунд, проблема исчезнет) ).

После некоторого исследования я обнаружил, что проблема заключалась в том, что я выполнял транзакцию "вручную" в моем JDBI, то есть я окружил свои утверждения с помощью BEGIN; ... COMMIT; и оказывается виновником!

В JDBI v2 я могу просто добавить аннотацию @Transaction, и операторы внутри @SqlQuery или @SqlUpdate будут выполняться как транзакция, и вышеупомянутой проблемы больше не будет!

Циньвэй Гун
источник
0

В моем случае я получал эту ошибку, потому что мой файл был поврежден. Итерируя записи файлов, он выдавал ту же ошибку.

Может быть, в будущем это кому-нибудь поможет. Это единственная причина, чтобы опубликовать этот ответ.

Бхарти Рават
источник
0

Я использую Spring с @Transactionalаннотацией, и я ловлю исключение, и для некоторого исключения я буду повторять 3 раза.

Для posgresql, когда получено исключение, вы не можете больше использовать одно и то же соединение для фиксации. Сначала необходимо выполнить откат.

В моем случае я использую, DatasourceUtilsчтобы получить текущее соединение и позвонить connection.rollback()вручную. И вызов метода recruive для повтора.

ysjiang
источник
0

Я работал с весенней загрузкой jpa и исправил, реализовав @EnableTransactionManagement

Прикрепленный файл может помочь вам.введите описание изображения здесь

Шахид Хуссейн Аббаси
источник
0

Я работал с весенней загрузкой jpa и исправил, реализовав @EnableTransactionManagement

Прикрепленный файл может помочь вам.

Шахид Хуссейн Аббаси
источник
0

Попробуй это COMMIT;

Я запускаю это в pgadmin4. Это может помочь. Это связано с преждевременной остановкой предыдущей команды

Филипп Кигени
источник
-1

Измените уровень изоляции с повторяемого чтения на прочитанное зафиксированное.

ericj
источник
-1

Установите для conn.setAutoCommit (false) значение conn.setAutoCommit (true)

Зафиксируйте транзакции перед началом новой.

абинаш саху
источник