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

152

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.

Voilà donc ce que je pense qu'il se passe:

  • Infinispan tente d'exécuter l' SELECT count(*)...instruction afin de voir s'il y a des enregistrements dans le ISPN_MIXED_BINARY_TABLE_configCache;
  • Postgres, pour une raison quelconque, n'aime pas cette affirmation.
  • Infinispan ignore cela et poursuit sa CREATE TABLEdéclaration.
  • Postgres barfs parce qu'il pense toujours que c'est la même transaction, qu'Infinispan n'a pas réussi à annuler, et cette transaction est tirée de la première SELECT count(*)...instruction.

Que signifie cette erreur et une idée comment la contourner?

Jimidy
la source
Juste si vous êtes venu ici comme moi à la recherche de ce qui précède PSQLException: current transaction is aborted...( 25P02) et peut-être aussi JPAou Hibernate. Finalement, c'était à cause de notre (belle!) Utilisation de Logback alimenté par un toString()objet DAO surchargé qui a causé l'erreur et a été bien avalé (mais accidentellement inaperçu par moi): log.info( "bla bla: {}", obj )produit bla bla: [FAILED toString()]. le modifier pour le log.info( "bla bla: {}", String.valueOf( obj )rendre sûr nul, mais sans l'avaler et laisser ainsi la transaction ouverte échouant sur une requête non liée.
Andreas Dietrich
J'obtenais le même type d'erreur. J'ai dû libérer la connexion avant le SQL. Le code de la mine était connection.commit ()
md. ariful ahsan

Réponses:

203

J'ai eu cette erreur en utilisant Java et postgresql en faisant 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é:

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

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

En utilisant la version java: Java 1.7

Voici l'instruction de création de table pour illustrer 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 produit 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

Solutions de contournement:

Vous avez quelques options:

  1. Solution la plus simple: ne participez pas à une transaction. Réglez le connection.setAutoCommit(false);sur connection.setAutoCommit(true);. Cela fonctionne car le SQL échoué est simplement ignoré en tant qu'instruction SQL échouée. Vous êtes invités à échouer les déclarations SQL autant que vous le souhaitez 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 sur cette connexion à la base de données que vous le souhaitez.

  3. N'attrapez pas et ignorez l'exception qui est levée lorsqu'une instruction SQL échoue. Ensuite, le programme s'arrêtera sur la requête mal formée.

  4. Obtenez Oracle à la place, Oracle ne lève pas d'exception lorsque vous échouez une requête sur une connexion au sein d'une transaction et continuez à utiliser cette connexion.

Dans la défense de la décision de postgresql de faire les choses de cette façon ... Oracle a vous fait doux dans la location du milieu , vous faites des choses stupides et avec vue sur elle.

Eric Leschinski
la source
10
Lol @ Option 4 ... J'avais fait pas mal de développement dans Oracle, et j'ai récemment commencé à utiliser Postgres ... c'est vraiment ennuyeux que Postgres fasse cela, et maintenant nous devons vraiment réécrire une grande partie de notre programme que nous portez d'Oracle vers Postgres. Pourquoi n'y a-t-il pas une option comme la première pour le faire se comporter comme Oracle mais sans l'auto-commit ?
ADTC
2
Nous avons découvert après quelques essais que l' option 2 est la plus proche du comportement d'Oracle. Si vous devez émettre plusieurs mises à jour et qu'un échec ne doit pas arrêter les mises à jour suivantes, appelez simplement rollback()le Connectionquand un SQLExceptionest intercepté. [ Quoi qu'il en soit, j'ai réalisé que cela était conforme à la philosophie PostgreSQL de forcer l'utilisateur à tout rendre explicite, alors qu'Oracle a la philosophie de s'occuper implicitement de beaucoup de choses.]
ADTC
2
L'option 2 contient une branche impossible or commit/restart the transaction. Comme je peux le voir, il n'y a aucun moyen de s'engager après exception. Quand j'essaye de commettre - PostgreSQL dorollback
turbanoff
1
Je peux confirmer le problème soulevé par @turbanoff. Cela peut également être reproduit directement avec psql. (1) démarrer une transaction, (2) émettre des déclarations valides, (3) émettre une instruction invalide, (4) commit -> psql annulera plutôt que de valider.
Alphaaa
1
postgresql.org/message-id/op.ur57x9ue33x80h%40insanity.lain.pl une discussion intéressante sur ce sujet. Si ce problème est déclenché par une violation de contrainte, les développeurs de PostgreSQL recommandent de rechercher un conflit à l'avance (requête avant la mise à jour / insertion) ou d'utiliser savepointspour revenir au point précédant la mise à jour / l'insertion. Voir stackoverflow.com/a/28640557/14731 pour un exemple de code.
Gili
27

Vérifiez la sortie avant l'instruction qui a provoqué current transaction is aborted. Cela signifie généralement que la base de données a levé une exception que votre code avait ignorée et s'attend maintenant à ce 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.

Vous devez intercepter toutes les exceptions et les transactions d'annulation dans de tels cas.

Voici un problème similaire.

vyegorov
la source
C'est génial, sauf dans ce cas, ce serait Infinispan, une bibliothèque tierce, qui parle à Postgres, et non mon code.
Jimidy
Eh bien, la situation est toujours la même - la transaction doit être annulée. Vérifiez peut-être s'il existe une version plus récente de la bibliothèque que vous utilisez ou soulevez le problème dans leur outil de suivi des bogues. Si vous trouvez l'exact SQLqui a causé le problème, vous aurez un champ pour éliminer le problème en utilisant l'extensibilité PostgreSQL.
vyegorov
On dirait que vous avez confirmé mes soupçons - je vais maintenant regarder la source Infinispan 5.1.2.
Jimidy
Pour être honnête, dans la classe TableManipulation, il y a un try-catch autour de la tentative d'exécuter select count (*) .... Peut-être que le pilote Postgres ne lève pas l'une des exceptions attendues. Je vais connecter un débogueur à JBoss pour essayer d'en savoir plus.
Jimidy
Le code Infinispan en question a été suggéré dans ce bogue: issues.jboss.org/browse/ ... J'y ai attaché un débogueur fonctionnant sur une instance de JBoss 7.1.1 en direct et Postgres lance des exceptions aux bons endroits. Ce sont peut-être les instructions JdbcUtil.safeClose () qui ne font pas leur travail. Je vais le soulever avec Infinispan.
Jimidy
13

Je pense que la meilleure solution est d'utiliser java.sql.Savepoint.

Avant d'exécuter une requête qui peut lever SQLException, utilisez la méthode Connection.setSavepoint () et si une exception sera lancée, vous ne restaurez que sur ce point de sauvegarde et non sur toutes les transactions.

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

   }
}
Michał Orliński
la source
J'ai accidentellement voté à la baisse, je viens juste de le remarquer. Ce n'était pas intentionnel, je ne peux pas annuler tant que la réponse n'est pas modifiée.
cerberos
La méthode savepoint est la solution réelle. Fonctionne pour moi aussi dans l'environnement de PHP, Doctrine2 et Postgres (9.5). Merci
helvete
6

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

C'est désormais possible, en définissant

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

thierry masson
la source
5

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

thedanotto
la source
C'était aussi mon cas. J'ai pensé que ça devait être quelque chose de stupide, parce que je n'ai pas vraiment essayé de faire quelque chose d'aussi compliqué.
Tashows
4

La raison de cette erreur est qu'il existe une autre base de données avant que la mauvaise opération ne conduise à l'opération de base de données en cours ne peut pas être effectuée (J'utilise Google Traduction pour traduire mon chinois en anglais)

管 浩浩
la source
2

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

Dan Berindei
la source
2

Vous devez revenir en arrière. Le pilote JDBC Postgres est assez mauvais. Mais si vous souhaitez conserver votre transaction et simplement annuler 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);
}
}

En savoir plus ici:

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

Mariano L
la source
2

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

S. Perera
la source
C'était mon problème, les tableaux pour moi étaient à travers deux schémas différents.
tomate
0

C'est un comportement très étrange de PostgreSQL, il n'est même pas "conforme à la philosophie PostgreSQL de forcer 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 - il laisse le choix au développeur.

al0
la source
0

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

Gregb
la source
Je me rends compte que ce n'est pas la cause la plus courante, mais c'était le cas sur un serveur que l'on m'a demandé de dépanner. Je pense donc que cela devrait être répertorié comme une cause potentielle.
gregb
0

Je rencontre juste la même erreur. J'ai pu déterminer la cause première en activant le log_statement et le log_min_error_statement dans mon PostgreSQL local.

Je Visée cette

virtualpathum
la source
0

J'utilise JDBI avec Postgres et j'ai rencontré le même problème, c'est-à-dire qu'après une violation d'une contrainte d'une déclaration de transaction précédente, les instructions suivantes échoueraient (mais après avoir attendu un moment, disons 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 j'ai entouré mes déclarations avec BEGIN; ... COMMIT; et il s'avère que c'est le coupable!

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

Qinwei Gong
la source
0

Dans mon cas, j'obtenais cette erreur car mon fichier était corrompu. En itérant les enregistrements de fichiers, cela me donnait la même erreur.

Peut-être que dans le futur cela aidera n'importe qui. C'est la seule raison de publier cette réponse.

Bharti Rawat
la source
0

J'utilise le ressort avec @Transactionalannotation, et j'attrape l'exception et pour quelques exceptions, je réessayerai 3 fois.

Pour posgresql, en cas d'exception, vous ne pouvez plus utiliser la même connexion pour valider. Vous devez d'abord annuler.

Dans mon cas, j'utilise DatasourceUtilspour obtenir la connexion actuelle et appeler connection.rollback()manuellement. Et l'appel à la méthode recruive pour réessayer.

Ysjiang
la source
0

Je travaillais avec Spring Boot jpa et je l'ai corrigé en implémentant @EnableTransactionManagement

Le fichier joint peut vous aider.entrez la description de l'image ici

Shahid Hussain Abbasi
la source
0

Je travaillais avec Spring Boot jpa et je l'ai corrigé en implémentant @EnableTransactionManagement

Le fichier joint peut vous aider.

Shahid Hussain Abbasi
la source
0

Essaye ça COMMIT;

Je lance cela dans pgadmin4. Cela peut aider. Cela a à voir avec l'arrêt prématuré de la commande précédente

Phillip Kigenyi
la source
-1

Modifiez le niveau d'isolement de lecture répétable à lecture validée.

Ericj
la source
-1

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

Validez les transactions avant d'en lancer une nouvelle.

abinash sahoo
la source