Vous n'êtes pas identifié(e).
Pages : 1
Bonjour,
j'ai une fonction java qui fait une série de insert et fait un seul commit tout à la fin de la fonction.
Avec Oracle, si je rencontre un problème (duplication de clé par exemple), l’exception est ignorée et je continu le traitement normalement (on affiche les erreurs dans la log).
Je souhaite conservé ce système avec Postgres, mais s’il rencontre une erreur, toutes les requêtes suivantes sont ignorées (ERREUR: la transaction est annulée, les commandes sont ignorées jusqu'à la fin du bloc).
Est-il possible d’ignorer cette erreur et de ne pas bloquer les requêtes suivantes en conservant des performances assez semblables ?
Merci
Hors ligne
A ma connaissance il faut rendre les contraintes DEFERRABLE. Et encore certaines ne le sont pas (NOT NULL et CHECK constraints).
Voir la documentation (partie DEFERRABLE, NOT DEFERRABLE)
Éric
Hors ligne
J'aurais tendance à dire que continuer après une erreur, ce n'est pas une manière propre de programmer...
Ceci dit, si c'est une série d'insertions indépendantes, tu peux toujours faire un point de sauvegarde (savepoint) entre chaque insert. Sur une erreur, faire un rollback to savepoint, et repartir sur les instructions suivant celle qui a causé l'erreur.
Enfin, je ne le ferai pas, surtout pas sans avoir analysé l'erreur au minimum (si tu te retrouves avec une erreur systématique comme un disque plein, ça va être long...).
Hors ligne
En fait, ce que vous voulez, c'est que seul l'ordre ayant généré l'erreur soit annulé, et pas toute la transaction.
Le plus simple est dans ce cas de faire un savepoint avant chaque ordre, et un rollback to savepoint en cas d'erreur (oui, cela signifie gérer les erreurs…). PostgreSQL ne vous laisse pas ne pas gérer les erreurs.
Vous pouvez aussi faire votre série d'insert en appelant une fonction PL qui fera ça toute seule (avec un bloc PL et une exception).
Évidemment, tous ces savepoint, ça va vous coûter en temps réseau (ça fait des dialogues client/serveur en plus).
Il y a aussi la solution de patcher le driver jdbc: http://postgresql.1045698.n5.nabble.com … 75906.html
Marc.
Hors ligne
Bonjour,
Merci pour vos réponse, apparement le plus simple dans mon cas est l'utilisation des savepoints.
J'aurais une petite question à ce sujet, avant de créer un savepoint, pour économiser de la place, je supprime le précédent avec un "RELEASE SAVEPOINT mon_pointdesauvegarde". Si mon_pointdesauvegarde n'existe pas, Postgres se met en erreur. Est-il possible de faire un "RELEASE SAVEPOINT IF EXIST mon_pointdesauvegarde" ou quelques chose qui serait équivalent ?
Merci
Hors ligne
Non ce n'est pas possible.
C'est plutôt compréhensible car c'est un mécanisme pour gérer les erreurs, il faut donc s'assurer que les instructions soient au bons endroits et bien exécutées.
Dernière modification par rjuju (13/06/2012 16:50:11)
Julien.
https://rjuju.github.io/
Hors ligne
Question bête : pourquoi ne pas sortir de transaction et passer en autocommit ? il ne reste plus qu'a gérer (ou pas) les erreurs de traitements.
Dernière modification par arthurr (13/06/2012 17:23:30)
Hors ligne
brse: plus simple: si vous créez un nouveau savepoint avec le même nom que l'ancien, il le remplace.
Marc.
Hors ligne
Question bête : pourquoi ne pas sortir de transaction et passer en autocommit ? il ne reste plus qu'a gérer (ou pas) les erreurs de traitements.
C'est une solution mais si on a une coupure de courant pendant le traitement, il ne faut pas que les modifications soit commiter.
brse: plus simple: si vous créez un nouveau savepoint avec le même nom que l'ancien, il le remplace.
J'ai essayé mais ce n'est pas le cas.
Regardez la dernière ligne de cette page : http://docs.postgresql.fr/9.1/sql-savepoint.html
En gros, tout les savepoints sont gardés en mémoire et du coup, au bout de 10.000 savepoints, j'ai une erreur concernant la mémoire.
PS : j'ai oublier de préciser, c'est à travers le JDBC en java que mes requêtes sont exécutées.
Hors ligne
Oui, vous allez tomber à court de verrous, effectivement, vu que vous allez créer un identifiant de transaction supplémentaire à chaque fois.
Ce que vous pouvez faire (c'est ce que je viens de tester, et que vous avez testé avant):
BEGIN;
savepoint s1;
insert into test values (0);
release savepoint s1;savepoint s1;
insert into test values (1);
release savepoint s1;savepoint s1;
insert into test values (2);
release savepoint s1;savepoint s1;
insert into test values (3);
Je viens d'envoyer ça pour 1000000 d'enregistrements, ça marche très bien (et ça va bien plus vite qu'en gardant les savepoints, ce que je fais d'habitude en ligne de commande par paresse )
Envoyer le release et le savepoint en une seule commande, c'est juste pour économiser un dialogue client/serveur. À vous de voir si vous y gagnez en java. Avec psql, le gain était faible, mais tout tournait sur la même machine. Et sinon, non, il n'y a pas moyen de ne pas avoir d'erreur avec un release savepoint qui n'existe pas. Vous avez plutôt intérêt à intégrer ça dans votre code.
Marc.
Hors ligne
Pages : 1