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(*)...оператора.

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


Просто если вы пришли сюда, как я в поисках выше 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. Обычно это означает, что база данных вызвала исключение, которое ваш код проигнорировал, и теперь ожидает, что следующие запросы вернут некоторые данные.

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

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

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


Это здорово, за исключением того, что в данном случае это будет 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 я создал миграцию, перенес свою БД, но забыл перезапустить сервер разработки. Я перезапустил свой сервер, и он работал.


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

4

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



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

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


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

0

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


0

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


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


0

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

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

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


0

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

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


0

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

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

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




0

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

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


-1

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


-1

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.