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.

Отже, ось що я думаю, що відбувається:

  • Infinispan намагається запустити SELECT count(*)...оператор, щоб перевірити, чи є записи в ISPN_MIXED_BINARY_TABLE_configCache;
  • Постгресу чомусь це твердження не подобається.
  • Infinispan ігнорує це і випереджує CREATE TABLEзаяву.
  • Postgres barfs, оскільки він все ще вважає, що це та сама транзакція, яку Infinispan не вдалося відмовити, і ця транзакція відхилена від першого SELECT count(*)...твердження.

Що означає ця помилка та будь-яка ідея, як її обходити?


Просто якщо ви приїхали сюди, як я, шукаючи вище PSQLException: current transaction is aborted...( 25P02), а може, також JPAабо Hibernate. Нарешті, це було завдяки нашому (приємному!) Використанню вхідного повідомлення, що подається із toString()завантаженим об'єктом DAO, що спричинило помилку і було добре проковтнуто (але випадково непомічене мною): log.info( "bla bla: {}", obj )вироблено bla bla: [FAILED toString()]. змінивши його, log.info( "bla bla: {}", String.valueOf( obj )зробивши його недійсним, але не проковтнувши, і, таким чином, залишити транзакцію відкритою не вдалося за незв’язаним запитом.
Андреас Дітріх

Я отримував помилки одного типу. Мені довелося відпустити з'єднання перед sql. Мій код був connection.commit ()
md. ariful ahsan

Відповіді:


203

Я отримав цю помилку, використовуючи Java та postgresql, роблячи вставку на столі. Я проілюструю, як можна відтворити цю помилку:

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

Підсумок:

Причина, за якою ви отримуєте цю помилку, полягає в тому, що ви ввели транзакцію, і один з ваших SQL-запитів не вдався, і ви помилили цю помилку і проігнорували її. Але цього було недостатньо, КОЛИ ви використовували те саме з'єднання, використовуючи SAME TRANSACTION для запуску іншого запиту. Виняток потрапляє на другий, правильно сформований запит, оскільки ви використовуєте зламану транзакцію для додаткової роботи. 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 dorollback
turbanoff

1
Я можу підтвердити проблему, яку порушив @turbanoff. Це також можна відтворити безпосередньо за допомогою psql. (1) розпочати транзакцію, (2) випустити деякі дійсні заяви, (3) видати недійсну заяву, (4) здійснити -> psql буде відкидати, а не робити.
Альфаа

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 була запропонована в цій помилці: issues.jboss.org/browse/… Я додав до нього налагоджувач, що працює на прямому екземплярі JBoss 7.1.1, і Postgres викидає винятки в потрібні місця. Можливо, саме JdbcUtil.safeClose () заяви не виконують свою роботу. Я підніму його разом з Інфініспаном.
Джиміді

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) {}

   }
}

Я випадково якось заперечив, тільки що помітив. Це не було навмисно, я не можу скасувати, якщо відповідь не буде відредагована.
cerberos

Спосіб збереження точки - це власне рішення. Також працює для мене в середовищі PHP, Doctrine2 та Postgres (9.5). Спасибі
helvete

6

З драйвером JDBC 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

Це може статися, якщо у вас немає місця на диску на гучності.


Я усвідомлюю, що це не найпоширеніша причина, але це було у випадку з сервером, який мене попросили усунути. Тому я думаю, що це має бути зазначено як потенційна причина.
gregb


0

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

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

У JDBI v2 я можу просто додати анотацію @Transaction, і висловлювання в межах @SqlQuery або @SqlUpdate будуть виконані як транзакції, і вищезазначена проблема більше не виникає!


0

У моєму випадку я отримував цю помилку, оскільки мій файл був пошкоджений. Під час ітерації записів файлів він давав мені таку саму помилку.

Можливо, в майбутньому це допоможе будь-кому. Це єдина причина опублікувати цю відповідь.


0

Я використовую весну з @Transactionalанотацією, і я виловлю виняток, і за деяким винятком я повторю спробу 3 рази.

Для posgresql, коли отримано виняток, ви не можете використовувати те саме З'єднання, щоб скористатися більше. Спершу потрібно відкататись.

У моєму випадку я використовую DatasourceUtilsдля отримання поточного з'єднання та дзвінка connection.rollback()вручну. І виклик методу рекрут для повторного спроби.


0

Я працював з весняним завантаженням jpa і виправлявся, застосовуючи @EnableTransactionManagement

Доданий файл може вам допомогти.введіть тут опис зображення


0

Я працював з весняним завантаженням jpa і виправлявся, застосовуючи @EnableTransactionManagement

Доданий файл може вам допомогти.


0

Спробуйте це COMMIT;

Я запускаю це в pgadmin4. Це може допомогти. Це стосується попередньої зупинки попередньої команди


-1

Змініть рівень ізоляції з повторюваного читання на вчинене читання.


-1

Встановити conn.setAutoCommit (помилково) на conn.setAutoCommit (вірно)

Здійсніть трансакції перед початком нової.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.