PSQLException: bieżąca transakcja jest przerywana, polecenia ignorowane do końca bloku transakcji


152

Widzę następujący (obcięty) ślad stosu w pliku 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

Przeglądanie pliku dziennika Postgres ujawnia następujące stwierdzenia:

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

Używam Infinispana dostarczanego z JBoss 7.1.1 Final, czyli 5.1.2.Final.

Więc myślę, że tak się dzieje:

  • Infinispan próbuje uruchomić SELECT count(*)...instrukcję, aby sprawdzić, czy są jakieś rekordy w ISPN_MIXED_BINARY_TABLE_configCache;
  • Postgres z jakiegoś powodu nie lubi tego stwierdzenia.
  • Infinispan ignoruje to i kontynuuje CREATE TABLEoświadczenie.
  • Postgres barfs, ponieważ nadal uważa, że ​​jest to ta sama transakcja, której Infinispan nie mógł wycofać, a ta transakcja jest przenoszona z pierwszego SELECT count(*)...oświadczenia.

Co oznacza ten błąd i jak można go obejść?


Po prostu jeśli przyszedłeś tutaj, tak jak ja, szukając powyższego PSQLException: current transaction is aborted...( 25P02), a może także JPAlub Hibernate. W końcu było to spowodowane naszym (fajnym!) Wykorzystaniem Logbacka zasilanego toString()-przeciążonym obiektem DAO, który spowodował błąd i został ładnie połknięty (ale przypadkowo niezauważony przeze mnie): log.info( "bla bla: {}", obj )wyprodukowany bla bla: [FAILED toString()]. zmieniając go tak, aby log.info( "bla bla: {}", String.valueOf( obj )był bezpieczny dla wartości null, ale nie połykał go, a tym samym pozostawiał otwartą transakcję, która kończy się niepowodzeniem w przypadku niepowiązanego zapytania.
Andreas Dietrich

Otrzymałem ten sam typ błędu. Musiałem zwolnić połączenie, zanim sql. Mój kod to connection.commit ()
md. ariful ahsan

Odpowiedzi:


203

Otrzymałem ten błąd przy użyciu Javy i postgresql robiąc wstawkę na stole. Zilustruję, jak można odtworzyć ten błąd:

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

Podsumowanie:

Powodem, dla którego otrzymujesz ten błąd, jest to, że wprowadziłeś transakcję, a jedno z zapytań SQL nie powiodło się, a Ty pochłonąłeś ten błąd i zignorowałeś go. Ale to nie wystarczyło, WTEDY użyłeś tego samego połączenia, używając TEJ SAMEJ TRANSAKCJI do uruchomienia kolejnego zapytania. Wyjątek jest zgłaszany przy drugim, poprawnie sformułowanym zapytaniu, ponieważ używasz uszkodzonej transakcji do wykonania dodatkowej pracy. Postgresql domyślnie powstrzymuje Cię przed tym.

Używam: 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".

Mój sterownik postgresql to: postgresql-9.2-1000.jdbc4.jar

Używając wersji java: Java 1.7

Oto instrukcja tworzenia tabeli ilustrująca wyjątek:

CREATE TABLE moobar
(
    myval   INT
);

Program Java powoduje błąd:

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();
    }   

}

Powyższy kod daje mi takie wyjście:

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

Obejścia:

Masz kilka opcji:

  1. Najprostsze rozwiązanie: nie bierz udziału w transakcji. Ustaw connection.setAutoCommit(false);na connection.setAutoCommit(true);. Działa, ponieważ nieudana instrukcja SQL jest po prostu ignorowana jako nieudana instrukcja sql. Możesz zawieść wszystkie instrukcje sql, a postgresql cię nie powstrzyma.

  2. Pozostań w transakcji, ale kiedy wykryjesz, że pierwszy sql nie powiódł się, wycofaj / uruchom ponownie lub zatwierdź / zrestartuj transakcję. Następnie możesz kontynuować niepowodzenie dowolnej liczby zapytań sql w tym połączeniu z bazą danych.

  3. Nie przechwytuj i nie ignoruj ​​wyjątku, który jest generowany, gdy instrukcja sql nie powiedzie się. Następnie program zatrzyma się na źle sformułowanym zapytaniu.

  4. Zamiast tego pobierz Oracle, Oracle nie zgłasza wyjątku, gdy zapytanie dotyczące połączenia w ramach transakcji zakończy się niepowodzeniem i nadal będzie korzystać z tego połączenia.

W obronie decyzji PostgreSQL do robienia rzeczy w ten sposób ... Oracle została czyni cię miękki w środku pozwalając robić głupie rzeczy i wychodzi to.


10
Lol @ Option 4 ... Zrobiłem sporo rozwoju w Oracle, a ostatnio zacząłem używać Postgres ... to naprawdę denerwujące, że Postgres to robi, a teraz musimy naprawdę przepisać dużą część naszego programu, przenoszą się z Oracle do Postgres. Dlaczego nie ma opcji takiej jak pierwsza, która sprawiłaby, że zachowuje się jak Oracle, ale bez automatycznego zatwierdzania ?
ADTC,

2
Po kilku próbach dowiedziałem się, że opcja 2 jest najbardziej zbliżona do zachowania Oracle. Jeśli trzeba wydawać wiele aktualizacji i jedna porażka nie powinna powstrzymać kolejne aktualizacje, wystarczy zadzwonić rollback()na Connectionkiedy SQLExceptionzostanie złapany. [W każdym razie zdałem sobie sprawę, że jest to zgodne z filozofią PostgreSQL polegającą na zmuszaniu użytkownika do
wyrażania

2
Opcja 2 zawiera niemożliwą gałąź or commit/restart the transaction. Jak widzę, nie ma sposobu, aby zatwierdzić po wyjątku. Kiedy próbuję zatwierdzić - PostgreSQLrollback
turbanoff

1
Mogę potwierdzić problem zgłoszony przez @turbanoff. Można to również odtworzyć bezpośrednio za pomocą psql. (1) rozpocząć transakcję, (2) wydać kilka ważnych instrukcji, (3) wydać niepoprawną instrukcję, (4) zatwierdzić -> psql zamiast zatwierdzać wycofa zmiany.
Alphaaa

1
postgresql.org/message-id/op.ur57x9ue33x80h%40insanity.lain.pl interesująca dyskusja na ten temat. Jeśli ten problem jest wywoływany przez naruszenie ograniczenia, twórcy PostgreSQL zalecają wcześniejsze sprawdzenie konfliktu (zapytanie przed aktualizacją / wstawieniem) lub skorzystanie savepointsz funkcji cofnięcia do punktu sprzed aktualizacji / wstawienia. Przykładowy kod znajdziesz na stackoverflow.com/a/28640557/14731 .
Gili,

27

Sprawdź dane wyjściowe przed instrukcją, która spowodowała current transaction is aborted. Zwykle oznacza to, że baza danych zgłosiła wyjątek, który Twój kod zignorował i teraz oczekuje, że kolejne zapytania zwrócą część danych.

Masz więc teraz niezgodność stanu między aplikacją, która uważa, że ​​wszystko jest w porządku, a bazą danych, która wymaga wycofania i ponownego rozpoczęcia transakcji od początku.

W takich przypadkach należy wyłapać wszystkie wyjątki i transakcje wycofania.

Oto podobny problem.


To świetnie, z wyjątkiem tego, że w tym przypadku byłby to Infinispan, biblioteka innej firmy, rozmawiająca z Postgresem, a nie z moim kodem.
Jimidy

Cóż, sytuacja wciąż taka sama - transakcja musi zostać wycofana. Może sprawdź, czy istnieje nowsza wersja biblioteki, której używasz, lub zgłoś problem w ich narzędziu do śledzenia błędów. Jeśli znajdziesz dokładnie to, SQLco spowodowało problem, będziesz mieć pole do wyeliminowania problemu za pomocą rozszerzalności PostgreSQL.
vyegorov

Wygląda na to, że potwierdziłeś moje podejrzenia - przyjrzę się teraz źródłu Infinispan 5.1.2.
Jimidy

Aby być uczciwym, w klasie TableManipulation istnieje próba przechwycenia wokół próby uruchomienia select count (*) .... Być może sterownik Postgres nie zgłasza żadnego z oczekiwanych wyjątków. Podłączę debugger do JBoss, aby dowiedzieć się więcej.
Jimidy

Kwestionowany kod Infinispan został zasugerowany w tym błędzie: Issues.jboss.org/browse/… Dołączyłem do niego debugger działający na żywej instancji JBoss 7.1.1 i Postgres rzuca wyjątki we właściwych miejscach. Być może to instrukcje JdbcUtil.safeClose () nie wykonują swojej pracy. Podniosę to z Infinispanem.
Jimidy

13

Myślę, że najlepszym rozwiązaniem jest użycie java.sql.Savepoint.

Przed wykonaniem zapytania, które może rzucić SQLException, użyj metody Connection.setSavepoint () i jeśli wyjątek zostanie zgłoszony, możesz tylko wycofać się do tego punktu zapisu, a nie wycofać całą transakcję.

Przykładowy kod:

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

   }
}

Przypadkowo jakoś przegłosowałem, dopiero co zauważyłem. Nie było to zamierzone, nie mogę cofnąć, chyba że odpowiedź zostanie zmieniona.
cerberos

Rzeczywistym rozwiązaniem jest metoda Savepoint. U mnie działa również w środowisku PHP, Doctrine2 i Postgres (9.5). Dzięki
helvete

6

Wykonano pewną pracę nad sterownikiem JDBC postgresql związaną z tym zachowaniem:
zobacz https://github.com/pgjdbc/pgjdbc/pull/477

Jest to teraz możliwe poprzez ustawienie

autosave = zawsze
w połączeniu (patrz https://jdbc.postgresql.org/documentation/head/connect.html ), aby uniknąć syndromu „bieżąca transakcja została przerwana”.
Narzut związany z obsługą punktu zapisu wokół wykonania instrukcji jest utrzymywany na bardzo niskim poziomie (szczegóły w powyższym linku).


5

W Ruby on Rails PG utworzyłem migrację, przeprowadziłem migrację mojej bazy danych, ale zapomniałem zrestartować serwer deweloperski. Zrestartowałem serwer i zadziałało.


Tak też było w moim przypadku. Pomyślałem, że to powinno być coś głupiego, ponieważ tak naprawdę nie próbowałem zrobić nic tak skomplikowanego.
Tashows

4

Powodem tego błędu jest to, że istnieje inna baza danych, zanim niewłaściwa operacja doprowadzi do bieżącej operacji bazy danych nie może zostać wykonana (używam tłumaczenia google, aby przetłumaczyć mój chiński na angielski)



2

Musisz wycofać. Sterownik JDBC Postgres jest dość zły. Ale jeśli chcesz zachować transakcję i po prostu cofnąć ten błąd, możesz użyć punktów zapisu:

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

Przeczytaj więcej tutaj:

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


2

Miałem ten sam problem, ale potem zdałem sobie sprawę, że w bazie danych znajduje się tabela o tej samej nazwie. Po usunięciu udało mi się zaimportować plik.


To był mój problem, tabele dla mnie obejmowały dwa różne schematy.
pomidor

0

Jest to bardzo dziwne zachowanie PostgreSQL, nawet nie jest to „zgodne z filozofią PostgreSQL, polegającą na zmuszaniu użytkownika do wyrażania wszystkiego jawnie” - ponieważ wyjątek został przechwycony i wyraźnie zignorowany. Więc nawet ta obrona nie wytrzymuje. Oracle w tym przypadku zachowuje się dużo bardziej przyjaznie dla użytkownika i (jak dla mnie) poprawnie - pozostawia wybór deweloperowi.


0

Może się tak zdarzyć, jeśli na woluminie brakuje miejsca na dysku.


Zdaję sobie sprawę, że nie jest to najczęstsza przyczyna, ale tak było na serwerze, na którym zostałem poproszony o rozwiązanie problemu. Więc myślę, że to powinno zostać wymienione jako potencjalna przyczyna.
gregb


0

Używam JDBI z Postgresem i napotkałem ten sam problem, tj. Po naruszeniu jakiegoś ograniczenia z zestawienia poprzedniej transakcji, kolejne wyciągi zawiodłyby (ale po odczekaniu, powiedzmy 20-30 sekund, problem znika ).

Po kilku poszukiwaniach stwierdziłem, że problem polegał na tym, że wykonywałem transakcje „ręcznie” w moim JDBI, tj. Otoczyłem moje oświadczenia słowem BEGIN; ... COMMIT; i okazuje się być winowajcą!

W JDBI v2 mogę po prostu dodać adnotację @Transaction, a wyciągi w @SqlQuery lub @SqlUpdate zostaną wykonane jako transakcja, a wspomniany problem już się nie zdarza!


0

W moim przypadku otrzymałem ten błąd, ponieważ mój plik był uszkodzony. Podczas iteracji rekordów plików dawał mi ten sam błąd.

Może w przyszłości pomoże każdemu. To jedyny powód, aby opublikować tę odpowiedź.


0

Używam sprężyny z @Transactionaladnotacją i wychwytuję wyjątek i dla jakiegoś wyjątku spróbuję ponownie 3 razy.

W przypadku posgresql, gdy pojawi się wyjątek, nie możesz już używać tego samego połączenia do zatwierdzenia. Najpierw musisz wycofać.

W moim przypadku używam, DatasourceUtilsaby uzyskać bieżące połączenie i dzwonić connection.rollback()ręcznie. I wywołaj metodę recruive, aby ponowić próbę.




0

Spróbuj tego COMMIT;

Uruchamiam to w pgadmin4. To może pomóc. Ma to związek z przedwczesnym zatrzymaniem poprzedniego polecenia


-1

Zmień poziom izolacji z odczytu powtarzalnego na przeczytany zatwierdzony.


-1

Ustaw conn.setAutoCommit (false) na conn.setAutoCommit (true)

Zatwierdź transakcje przed zainicjowaniem nowej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.