PSQLException: la transacción actual se cancela, los comandos se ignoran hasta el final del bloque de transacción

152

Veo el siguiente stacktrace (truncado) en el archivo server.log de 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

La inspección del archivo de registro de Postgres revela las siguientes declaraciones:

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

Estoy usando el Infinispan enviado con JBoss 7.1.1 Final, que es 5.1.2.Final.

Entonces esto es lo que creo que está sucediendo:

  • Infinispan intenta ejecutar la SELECT count(*)...instrucción para ver si hay registros en el ISPN_MIXED_BINARY_TABLE_configCache;
  • Postgres, por alguna razón, no le gusta esta declaración.
  • Infinispan ignora esto y sigue adelante con la CREATE TABLEdeclaración.
  • Postgres vomita porque todavía piensa que es la misma transacción, que Infinispan no pudo revertir, y esta transacción se basa en la primera SELECT count(*)...declaración.

¿Qué significa este error y alguna idea de cómo solucionarlo?

Jimidy
fuente
Solo si viniste aquí como yo buscando lo anterior PSQLException: current transaction is aborted...( 25P02) y tal vez también JPAo Hibernate. Finalmente, se debió a nuestro (¡bueno!) Uso de Logback alimentado con un toString()objeto DAO sobrecargado que causó el error y fue muy bien tragado (pero accidentalmente desapercibido por mí): log.info( "bla bla: {}", obj )producido bla bla: [FAILED toString()]. cambiarlo para que log.info( "bla bla: {}", String.valueOf( obj )sea ​​nulo seguro, pero no tragarlo y, por lo tanto, dejar la transacción abierta fallando en una consulta no relacionada.
Andreas Dietrich
Estaba recibiendo el mismo tipo de error. Tuve que liberar la conexión antes del sql. El código de la mina fue connection.commit ()
md. ariful ahsan

Respuestas:

203

Recibí este error usando Java y postgresql haciendo una inserción en una tabla. Ilustraré cómo puedes reproducir este error:

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

Resumen:

La razón por la que obtiene este error es porque ingresó una transacción y una de sus consultas SQL falló, y engulló esa falla y la ignoró. Pero eso no fue suficiente, ENTONCES usó esa misma conexión, usando la MISMA TRANSACCIÓN para ejecutar otra consulta. La excepción se genera en la segunda consulta formada correctamente porque está utilizando una transacción rota para realizar un trabajo adicional. Postgresql por defecto le impide hacer esto.

Estoy usando: 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".

Mi controlador postgresql es: postgresql-9.2-1000.jdbc4.jar

Usando la versión de Java: Java 1.7

Aquí está la declaración de creación de tabla para ilustrar la excepción:

CREATE TABLE moobar
(
    myval   INT
);

El programa Java causa el error:

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

}

El código anterior produce esta salida para mí:

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

Soluciones alternativas:

Tienes pocas opciones:

  1. La solución más simple: no participe en una transacción. Establecer el connection.setAutoCommit(false);a connection.setAutoCommit(true);. Funciona porque el SQL fallido simplemente se ignora como una instrucción sql fallida. Usted puede fallar en las declaraciones de sql todo lo que quiera y postgresql no lo detendrá.

  2. Permanezca en una transacción, pero cuando detecte que el primer sql ha fallado, revierta / reinicie o confirme / reinicie la transacción. Luego puede continuar fallando tantas consultas sql en esa conexión de base de datos como desee.

  3. No atrape e ignore la excepción que se produce cuando falla una instrucción sql. Luego, el programa se detendrá en la consulta con formato incorrecto.

  4. Obtenga Oracle en su lugar, Oracle no lanza una excepción cuando falla una consulta en una conexión dentro de una transacción y continúa usando esa conexión.

En defensa de la decisión de postgresql de hacer las cosas de esta manera ... Oracle te estaba ablandando en el medio, permitiéndote hacer cosas tontas y pasarlo por alto.

revs Eric Leschinski
fuente
10
Lol @ Opción 4 ... Hice bastante desarrollo en Oracle, y recientemente comencé a usar Postgres ... es realmente molesto que Postgres haga esto, y ahora tenemos que reescribir una gran parte de nuestro programa. están portando de Oracle a Postgres. ¿Por qué no hay una opción como la primera para hacer que se comporte como Oracle pero sin la confirmación automática ?
ADTC
2
Después de algunas pruebas, descubrí que la Opción 2 es lo más cercano que puede llegar al comportamiento de Oracle. Si necesita ejecutar varias actualizaciones, y un fracaso no debe detener las actualizaciones posteriores, sólo tiene que llamar rollback()al Connectioncuando una SQLExceptionestaba. [ De todos modos, me di cuenta de que esto está en línea con la filosofía de PostgreSQL de obligar al usuario a hacer todo explícito, mientras que Oracle tiene la filosofía de ocuparse implícitamente de muchas cosas.]
ADTC
2
La opción 2 contiene una rama imposible or commit/restart the transaction. Como puedo ver, no hay forma de comprometerse después de una excepción. Cuando intento comprometerme - PostgreSQL dorollback
turbanoff
1
Puedo confirmar el problema planteado por @turbanoff. Esto también se puede reproducir directamente con psql. (1) iniciar una transacción, (2) emitir algunas declaraciones válidas, (3) emitir una declaración no válida, (4) commit -> psql revertirá en lugar de comprometerse.
Alphaaa
1
postgresql.org/message-id/op.ur57x9ue33x80h%40insanity.lain.pl una discusión interesante sobre este tema. Si este problema se desencadena por una violación de restricción, los desarrolladores de PostgreSQL recomiendan verificar un conflicto antes de tiempo (consulta antes de actualizar / insertar) o usar savepointspara retroceder al punto anterior a la actualización / inserción. Consulte stackoverflow.com/a/28640557/14731 para obtener un código de muestra.
Gili
27

Verifique la salida antes de la declaración que causó current transaction is aborted. Esto generalmente significa que la base de datos arrojó una excepción que su código había ignorado y ahora espera que las próximas consultas devuelvan algunos datos.

Entonces, ahora tiene una discrepancia de estado entre su aplicación, que considera que las cosas están bien, y la base de datos, que requiere que retroceda y reinicie su transacción desde el principio.

Debe capturar todas las excepciones y transacciones de reversión en tales casos.

Aquí hay un problema similar.

vyegorov
fuente
Eso es genial, excepto en este caso que sería Infinispan, una biblioteca de terceros, hablando con Postgres, y no mi código.
Jimidy
Bueno, la situación sigue siendo la misma: la transacción debe revertirse. Tal vez verifique si hay una versión más nueva de la biblioteca que está utilizando o plantee el problema dentro de su rastreador de errores. Si encuentra exactamente lo SQLque causó el problema, tendrá algún campo para eliminar el problema usando la extensibilidad de PostgreSQL.
vyegorov
Parece que has confirmado mis sospechas. Voy a ver la fuente Infinispan 5.1.2 ahora.
Jimidy
Para ser justos, en la clase TableManipulation, hay un intento de atrapar alrededor del intento de ejecutar select count (*) ... Quizás el controlador Postgres no está lanzando una de las excepciones esperadas. Conectaré un depurador a JBoss para tratar de obtener más información.
Jimidy
El código de Infinispan en cuestión se sugirió en este error: issues.jboss.org/browse/…. He adjuntado un depurador que se ejecuta en una instancia JBoss 7.1.1 en vivo y Postgres está lanzando excepciones en los lugares correctos. Quizás son las declaraciones JdbcUtil.safeClose () las que no están haciendo su trabajo. Lo plantearé con Infinispan.
Jimidy
13

Creo que la mejor solución es usar java.sql.Savepoint.

Antes de ejecutar la consulta que puede lanzar SQLException, use el método Connection.setSavepoint () y, si se produce una excepción, solo retrocederá a este punto de guardado, no revertirá todas las transacciones.

Código de ejemplo:

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
fuente
Accidentalmente voté en contra de alguna manera, solo me di cuenta. No fue intencional, no puedo deshacer a menos que se edite la respuesta.
cerberos
La forma de guardar puntos es la solución real. También funciona para mí en entornos de PHP, Doctrine2 y Postgres (9.5). Gracias
helvete
6

Se ha realizado un trabajo en el controlador JDBC postgresql, relacionado con este comportamiento:
consulte https://github.com/pgjdbc/pgjdbc/pull/477

Ahora es posible, configurando

autoguardado = siempre
en la conexión (consulte https://jdbc.postgresql.org/documentation/head/connect.html ) para evitar el síndrome de "la transacción actual se cancela".
La sobrecarga debida al manejo de un punto de rescate alrededor de la ejecución de la declaración se mantiene muy baja (consulte el enlace anterior para obtener más detalles).

Thierry Masson
fuente
5

En Ruby on Rails PG, había creado una migración, migré mi base de datos, pero olvidé reiniciar mi servidor de desarrollo. Reinicié mi servidor y funcionó.

thedanotto
fuente
Ese fue mi caso también. Pensé que debería ser algo estúpido, porque realmente no intenté hacer algo tan complicado.
Tashows
4

La razón de este error es que hay otra base de datos antes de que la operación incorrecta conduzca a la operación actual de la base de datos. No uso la traducción de Google para traducir mi chino al inglés.

管 浩浩
fuente
2

El problema se ha solucionado en Infinispan 5.1.5.CR1: ISPN-2023

Dan Berindei
fuente
2

Necesitas retroceder. El controlador JDBC Postgres es bastante malo. Pero si desea conservar su transacción y simplemente revertir ese error, puede usar los puntos de guardado:

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

Leer más aquí:

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

Mariano L
fuente
2

Tuve el mismo problema pero luego me di cuenta de que hay una tabla con el mismo nombre en la base de datos. Después de eliminar eso pude importar el archivo.

S.Perera
fuente
Este era mi problema, las tablas para mí estaban en dos esquemas diferentes.
tomate
0

Este es un comportamiento muy extraño de PostgreSQL, incluso no está "en línea con la filosofía de PostgreSQL de obligar al usuario a hacer todo explícito", ya que la excepción fue detectada e ignorada explícitamente. Entonces, incluso esta defensa no se sostiene. Oracle en este caso se comporta mucho más fácil de usar y (como para mí) correctamente: deja una opción para el desarrollador.

al0
fuente
0

Esto puede suceder si no tiene espacio en disco en el volumen.

gregb
fuente
Me doy cuenta de que esta no es la causa más común, pero este fue el caso en un servidor que me pidieron solucionar. Así que creo que esto debería enumerarse como una posible causa.
gregb
0

Estoy usando JDBI con Postgres, y encontré el mismo problema, es decir, después de una violación de alguna restricción de una declaración de transacción anterior, las declaraciones posteriores fallarían (pero después de esperar un tiempo, digamos 20-30 segundos, el problema desaparece )

Después de investigar un poco, descubrí que el problema era que estaba haciendo una transacción "manualmente" en mi JDBI, es decir, rodeé mis declaraciones con BEGIN; ... COMMIT; ¡y resulta ser el culpable!

En JDBI v2, solo puedo agregar la anotación @Transaction, y las declaraciones dentro de @SqlQuery o @SqlUpdate se ejecutarán como una transacción, ¡y el problema mencionado anteriormente ya no ocurre!

Qinwei Gong
fuente
0

En mi caso, recibí este error porque mi archivo estaba dañado. Mientras iteraba los registros de los archivos, me daba el mismo error.

Puede ser en el futuro ayudará a cualquiera. Esa es la única razón para publicar esta respuesta.

Bharti Rawat
fuente
0

Uso spring con @Transactionalanotaciones, y atrapo la excepción y para alguna excepción volveré a intentarlo 3 veces.

Para posgresql, cuando se obtiene una excepción, no puede usar la misma conexión para confirmar más. Debe retroceder primero.

Para mi caso, uso el DatasourceUtilspara obtener la conexión actual y llamar connection.rollback()manualmente. Y la llamada al método de reclutamiento para volver a intentar.

ysjiang
fuente
0

Estaba trabajando con Spring boot jpa y lo solucioné implementando @EnableTransactionManagement

El archivo adjunto puede ayudarlo.ingrese la descripción de la imagen aquí

Shahid Hussain Abbasi
fuente
0

Estaba trabajando con Spring boot jpa y lo solucioné implementando @EnableTransactionManagement

El archivo adjunto puede ayudarlo.

Shahid Hussain Abbasi
fuente
0

Prueba esto COMMIT;

Lo ejecuto en pgadmin4. Puede ayudar. Tiene que ver con que el comando anterior se detenga prematuramente

Phillip Kigenyi
fuente
-1

Cambie el nivel de aislamiento de lectura repetible a lectura confirmada.

ericj
fuente
-1

Establezca conn.setAutoCommit (false) en conn.setAutoCommit (true)

Comprometa las transacciones antes de iniciar una nueva.

abinash sahoo
fuente