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ść?

Jimidy
źródło
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.

Eric Leschinski
źródło
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.

vyegorov
źródło
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) {}

   }
}
Michał Orliński
źródło
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).

thierry masson
źródło
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.

thedanotto
źródł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)

管 浩浩
źródło
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

Mariano L
źródło
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.

S.Perera
źródło
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.

al0
źródło
0

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

gregb
źródło
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

Po prostu napotykam ten sam błąd. Udało mi się ustalić główną przyczynę, włączając log_statement i log_min_error_statement w moim lokalnym PostgreSQL.

Skierowałem to

virtualpathum
źródło
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!

Qinwei Gong
źródło
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ź.

Bharti Rawat
źródło
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ę.

ysjiang
źródło
0

Pracowałem z spring boot jpa i naprawiłem, wdrażając @EnableTransactionManagement

Załączony plik może ci pomóc.wprowadź opis obrazu tutaj

Shahid Hussain Abbasi
źródło
0

Pracowałem z spring boot jpa i naprawiłem, wdrażając @EnableTransactionManagement

Załączony plik może ci pomóc.

Shahid Hussain Abbasi
źródło
0

Spróbuj tego COMMIT;

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

Phillip Kigenyi
źródło
-1

Zmień poziom izolacji z odczytu powtarzalnego na przeczytany zatwierdzony.

ericj
źródło
-1

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

Zatwierdź transakcje przed zainicjowaniem nowej.

abinash sahoo
źródło