web-dev-qa-db-fra.com

PSQLException: la transaction en cours est abandonnée, les commandes sont ignorées jusqu'à la fin du bloc de transaction

Je vois le stacktrace suivant (tronqué) dans le fichier 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

L'inspection du fichier journal Postgres révèle les déclarations suivantes:

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

J'utilise l'Infinispan livré avec JBoss 7.1.1 Final, qui est 5.1.2.Final.

Donc, voici ce que je pense qui se passe:

  • Infinispan tente d'exécuter l'instruction SELECT count(*)... afin de voir s'il existe des enregistrements dans le ISPN_MIXED_BINARY_TABLE_configCache;
  • Postgres, pour une raison quelconque, n'aime pas cette déclaration.
  • Infinispan ignore cela et avance avec l'instruction CREATE TABLE.
  • Postgres barfs parce qu'il pense toujours que c'est la même transaction, qu'Infinispan n'a pas pu restaurer, et que cette transaction est gérée depuis la première instruction SELECT count(*)....

Qu'est-ce que cette erreur signifie et une idée sur la façon de la contourner?

118
Jimidy

J'ai eu cette erreur en utilisant Java et postgresql faire une insertion sur une table. Je vais illustrer comment vous pouvez reproduire cette erreur:

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

Résumé:

Si vous obtenez cette erreur, c'est parce que vous avez entré une transaction et qu'une de vos requêtes SQL a échoué, que vous avez englouti cet échec et que vous l'avez ignoré. Mais cela ne suffisait pas, ALORS vous avez utilisé la même connexion, en utilisant SAME TRANSACTION pour exécuter une autre requête. L'exception est levée sur la deuxième requête correctement formée parce que vous utilisez une transaction cassée pour effectuer un travail supplémentaire. Postgresql par défaut vous empêche de le faire.

J'utilise: 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".

Mon pilote postgresql est: postgresql-9.2-1000.jdbc4.jar

Utilisation de la version Java: Java 1.7

Voici l'instruction de création de table illustrant l'exception:

CREATE TABLE moobar
(
    myval   INT
);

Le programme Java provoque l'erreur:

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

}

Le code ci-dessus génère cette sortie pour moi:

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

Contournements:

Vous avez quelques options:

  1. Solution la plus simple: ne soyez pas dans une transaction. Définissez connection.setAutoCommit(false); sur connection.setAutoCommit(true);. Cela fonctionne parce qu'alors le SQL ayant échoué est simplement ignoré en tant qu'instruction SQL ayant échoué. Vous êtes le bienvenu pour faire échouer les déclarations SQL tout ce que vous voulez et postgresql ne vous arrêtera pas.

  2. Restez dans une transaction, mais lorsque vous détectez que le premier SQL a échoué, annulez/redémarrez ou validez/redémarrez la transaction. Ensuite, vous pouvez continuer à échouer autant de requêtes SQL que vous le souhaitez sur cette connexion à la base de données.

  3. Ne pas attraper et ignorer l'exception qui est levée quand une instruction SQL échoue. Ensuite, le programme s'arrêtera sur la requête malformée.

  4. Si vous obtenez Oracle, Oracle ne lève pas d'exception lorsque vous échouez à une requête sur une connexion dans une transaction et continuez à utiliser cette connexion. 

Pour défendre la décision de postgresql de faire les choses de cette façon ... Oracle vous rendait doux au milieu, vous permettant de faire des choses idiotes et de les ignorer.

157
Eric Leschinski

Vérifiez la sortie avant l'instruction à l'origine de current transaction is aborted. Cela signifie généralement que la base de données a généré une exception que votre code avait ignorée et attend maintenant que les prochaines requêtes renvoient des données.

Vous avez donc maintenant une incompatibilité d'état entre votre application, qui considère que tout va bien, et la base de données, qui vous oblige à annuler et à redémarrer votre transaction depuis le début.

Dans ce cas, vous devez intercepter toutes les exceptions et les transactions d'annulation.

Voici un problème similaire.

19
vyegorov

Je pense que la meilleure solution consiste à utiliser Java.sql.Savepoint.

Avant d'exécuter une requête qui peut générer une exception SQLException, utilisez la méthode Connection.setSavepoint () et, si une exception survient, vous restaurez uniquement la restauration de ce point de sauvegarde, pas la restauration complète.

Exemple de code:

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

   }
}
8
Michał Orliński

Dans Ruby on Rails PG, j'avais créé une migration, migré ma base de données, mais j'avais oublié de redémarrer mon serveur de développement. J'ai redémarré mon serveur et cela a fonctionné.

5
thedanotto

La raison de cette erreur est qu’il existe d’autres bases de données avant que la mauvaise opération qui a conduit à l’opération de base de données actuelle ne puisse pas être effectuée j’utilise la traduction google pour traduire mon chinois en anglais

3
管浩浩

Vous devez revenir en arrière. Le pilote JDBC Postgres est assez mauvais. Mais si vous souhaitez conserver votre transaction et annuler simplement cette erreur, vous pouvez utiliser des points de sauvegarde:

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

Lire la suite ici:

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

2
Mariano L

Le problème a été corrigé dans Infinispan 5.1.5.CR1: ISPN-2023

2
Dan Berindei

Des travaux ont été effectués sur le pilote JDBC postgresql, liés à ce problème:
voir https://github.com/pgjdbc/pgjdbc/pull/477

Il est maintenant possible, en mettant 

autosave = toujours
dans la connexion (voir https://jdbc.postgresql.org/documentation/head/connect.html ) pour éviter le syndroma 'La transaction en cours est annulée'.
La surcharge due à la gestion d'un point de sauvegarde autour de l'exécution de l'instruction est très faible (voir le lien ci-dessus pour plus de détails).

2
thierry masson

J'avais le même problème mais j'ai alors réalisé qu'il y avait une table du même nom dans la base de données. Après avoir supprimé cela, j'ai pu importer le fichier.

1
S.Perera

C'est un comportement très étrange de PostgreSQL, il n'est même pas "en ligne avec la philosophie de PostgreSQL consistant à obliger l'utilisateur à tout rendre explicite" - car l'exception a été interceptée et ignorée explicitement. Donc, même cette défense ne tient pas. Oracle dans ce cas se comporte beaucoup plus convivial et (comme pour moi) correctement - cela laisse un choix au développeur.

0
al0

Je viens de rencontrer la même erreur. J'ai pu comprendre la cause en activant les instructions log_statement et log_min_error_error dans ma version locale de PostgreSQL. 

J'ai référé this

0
virtualpathum

Définissez conn.setAutoCommit (false) sur conn.setAutoCommit (true)

Commettez les transactions avant d’en initier une nouvelle.

0
abinash sahoo

J'utilise JDBI avec Postgres et rencontre le même problème, c'est-à-dire qu'après violation d'une contrainte d'une déclaration d'une transaction précédente, les déclarations suivantes échouent (mais après avoir attendu un certain temps, par exemple 20-30 secondes, le problème disparaît ).

Après quelques recherches, j’ai trouvé que le problème était que je faisais une transaction "manuellement" dans mon JDBI, c’est-à-dire que je cernais mes déclarations avec BEGIN; ... COMMIT; et il s'avère que c'est le coupable!

Dans JDBI v2, je peux simplement ajouter une annotation @Transaction et les instructions contenues dans @SqlQuery ou @SqlUpdate seront exécutées en tant que transaction et le problème mentionné ci-dessus ne se produit plus!

0
Qinwei Gong

Cela peut arriver si vous manquez d'espace disque sur le volume.

0
gregb