8 min

Transactions Postgres pour flux de travail multi‑étapes : modèles pratiques

Apprenez les transactions Postgres pour les workflows multi‑étapes : regrouper les mises à jour, éviter les écritures partielles, gérer les reprises et maintenir la cohérence des données.

Transactions Postgres pour flux de travail multi‑étapes : modèles pratiques

Pourquoi les mises à jour multi-étapes finissent souvent par être incohérentes

La plupart des fonctionnalités réelles ne se réduisent pas à une seule mise à jour en base. Elles forment une courte chaîne : insérer une ligne, mettre à jour un solde, marquer un statut, écrire un enregistrement d'audit, peut‑être mettre un job en file. Une écriture partielle survient quand seulement certaines de ces étapes atteignent la base.

On le remarque généralement quand quelque chose interrompt la chaîne : une erreur serveur, un timeout entre votre appli et Postgres, un plantage après l'étape 2, ou une reprise qui réexécute l'étape 1. Chaque instruction peut être correcte isolément. Le flux se casse quand il s'arrête en cours de route.

On peut souvent le repérer rapidement :

  • Une ligne existe, mais une ligne liée manque (commande créée, aucun article)
  • De l'argent a été déplacé, mais le statut n'a pas changé (payé, toujours marqué impayé)
  • Deux enregistrements qui devraient n'en faire qu'un (abonnements en double après une reprise)
  • Des indicateurs contradictoires (l'utilisateur est "actif" mais n'a pas de plan)
  • Des états qui n'apparaissent que sous charge ou en cas d'erreurs

Un exemple concret : une montée en gamme met à jour le plan du client, ajoute un enregistrement de paiement et augmente les crédits disponibles. Si l'application plante après avoir enregistré le paiement mais avant d'ajouter les crédits, le support voit "payé" dans une table et "pas de crédits" dans une autre. Si le client relance, vous pouvez même enregistrer le paiement deux fois.

L'objectif est simple : traiter le workflow comme un interrupteur unique. Soit chaque étape réussit, soit aucune ne le fait, afin de ne jamais stocker un travail à moitié fini.

Les transactions, en termes simples

Une transaction est la façon dont la base de données dit : traitez ces étapes comme une seule unité de travail. Soit tous les changements ont lieu, soit aucun d'entre eux. Cela compte chaque fois que votre workflow nécessite plus d'une mise à jour, comme créer une ligne, mettre à jour un solde et écrire un journal d'audit.

Pensez au transfert d'argent entre deux comptes. Il faut soustraire du compte A et ajouter au compte B. Si l'application plante après la première étape, vous ne voulez pas que le système "se souvienne" uniquement de la soustraction.

Commit vs rollback

Quand vous committez, vous dites à Postgres : conservez tout ce que j'ai fait dans cette transaction. Tous les changements deviennent permanents et visibles par les autres sessions.

Quand vous rollbackez, vous dites à Postgres : oubliez tout ce que j'ai fait dans cette transaction. Postgres annule les changements comme si la transaction n'avait jamais eu lieu.

Ce que Postgres garantit (et ce qu'il ne garantit pas)

À l'intérieur d'une transaction, Postgres garantit que vous n'exposerez pas des résultats à moitié finis aux autres sessions avant votre commit. Si quelque chose échoue et que vous faites rollback, la base nettoie les écritures de cette transaction.

Une transaction ne remplace pas une mauvaise conception du workflow. Si vous soustrayez le mauvais montant, utilisez le mauvais ID utilisateur ou sautez une vérification nécessaire, Postgres commitera fidèlement le mauvais résultat. Les transactions n'empêchent pas non plus automatiquement tous les conflits métier (comme la survente de stock) à moins de les associer aux bonnes contraintes, verrous ou niveaux d'isolation.

Workflows qui devraient être regroupés

Chaque fois que vous mettez à jour plus d'une table (ou plus d'une ligne) pour réaliser une seule action réelle, vous avez un candidat pour une transaction. L'idée reste la même : ou tout est fait, ou rien ne l'est.

Le flux de commande est le cas classique. Vous pouvez créer une ligne de commande, réserver du stock, prélever un paiement, puis marquer la commande comme payée. Si le paiement réussit mais que la mise à jour du statut échoue, vous avez de l'argent capturé pour une commande qui semble toujours impayée. Si la ligne de commande est créée mais que le stock n'est pas réservé, vous pouvez vendre des articles que vous n'avez pas réellement.

L'onboarding utilisateur casse silencieusement de la même manière. Créer l'utilisateur, insérer un profil, attribuer des rôles et enregistrer l'envoi d'un e‑mail de bienvenue constituent une seule action logique. Sans regroupement, vous pouvez aboutir à un utilisateur qui peut se connecter mais sans permissions, ou à un profil existant sans utilisateur.

Les actions back‑office exigent souvent un comportement strict de "piste d'audit + changement d'état". Approuver une demande, écrire une entrée d'audit et mettre à jour un solde doivent réussir ensemble. Si le solde change mais que le journal d'audit manque, vous perdez la preuve de qui a changé quoi et pourquoi.

Les jobs en arrière‑plan en profitent aussi, surtout quand vous traitez un élément avec plusieurs étapes : réclamer l'item pour éviter que deux workers ne le fassent, appliquer la mise à jour métier, enregistrer un résultat pour le reporting et les reprises, puis marquer l'item comme terminé (ou échoué avec un motif). Si ces étapes se dispersent, les reprises et la concurrence créent un désordre.

Concevez le workflow avant d'écrire le SQL

Les fonctionnalités multi‑étapes cassent quand vous les traitez comme un tas de mises à jour indépendantes. Avant d'ouvrir un client de base de données, rédigez le workflow comme une courte histoire avec une seule ligne d'arrivée claire : qu'est‑ce qui compte exactement comme "terminé" pour l'utilisateur ?

Commencez par lister les étapes en langage courant, puis définissez une condition de succès unique. Par exemple : "La commande est créée, le stock est réservé et l'utilisateur voit un numéro de confirmation de commande." Tout ce qui est en dessous n'est pas un succès, même si certaines tables ont été mises à jour.

Ensuite, tracez une ligne nette entre le travail en base et le travail externe. Les étapes en base sont celles que vous pouvez protéger par des transactions. Les appels externes comme les paiements par carte, l'envoi d'e‑mails ou l'appel d'API tierces peuvent échouer de façon lente et imprévisible, et vous ne pouvez généralement pas les annuler.

Une approche simple de planification : séparer les étapes en (1) doivent être tout-ou-rien, (2) peuvent se produire après le commit.

Décidez ce qui appartient à la transaction

À l'intérieur de la transaction, ne gardez que les étapes qui doivent rester cohérentes ensemble :

  • Créer ou mettre à jour des lignes cœur (commande, facture, solde de compte)
  • Réserver des ressources partagées (stock, places, quota)
  • Enregistrer un événement durable de "quoi faire ensuite" (table outbox)
  • Faire respecter des règles avec des contraintes (clés uniques, clés étrangères)

Déplacez les effets secondaires à l'extérieur. Par exemple, committez d'abord la commande, puis envoyez l'e‑mail de confirmation à partir d'un enregistrement outbox.

Écrivez des attentes de rollback pour chaque étape

Pour chaque étape, écrivez ce qui doit se produire si l'étape suivante échoue. "Rollback" peut signifier un rollback de base, ou une action compensatoire.

Exemple : si le paiement réussit mais que la réservation de stock échoue, décidez à l'avance si vous remboursez immédiatement, ou si vous marquez la commande comme "paiement capturé, en attente de stock" et gérez cela de façon asynchrone.

Pas à pas : encapsuler un workflow dans une transaction

Une transaction dit à Postgres : traitez ces étapes comme une unité. Soit elles ont toutes lieu, soit aucune. C'est la façon la plus simple d'éviter les écritures partielles.

Le flux de base

Utilisez une seule connexion de base de données (une session) du début à la fin. Si vous répartissez les étapes sur différentes connexions, Postgres ne peut pas garantir le résultat tout‑ou‑rien.

La séquence est simple : begin, exécutez les lectures et écritures nécessaires, commit si tout réussit, sinon rollback et renvoyez une erreur claire.

Voici un exemple minimal en SQL :

BEGIN;

-- reads that inform your decision
SELECT balance FROM accounts WHERE id = 42 FOR UPDATE;

-- writes that must stay together
UPDATE accounts SET balance = balance - 50 WHERE id = 42;
INSERT INTO ledger(account_id, amount, note) VALUES (42, -50, 'Purchase');

COMMIT;

-- on error (in code), run:
-- ROLLBACK;

Gardez-la courte (et débogable)

Les transactions détiennent des verrous pendant leur exécution. Plus vous les gardez ouvertes longtemps, plus vous bloquez les autres travaux et plus vous risquez des timeouts ou des deadlocks. Faites l'essentiel dans la transaction, et déplacez les tâches lentes (envoi d'e‑mails, appels à des prestataires de paiement, génération de PDF) à l'extérieur.

Quand quelque chose échoue, loggez suffisamment de contexte pour reproduire le problème sans divulguer de données sensibles : nom du workflow, order_id ou user_id, paramètres clés (montant, devise) et le code d'erreur Postgres. Évitez de logger des payloads complets, des données de carte ou des informations personnelles.

Notions de concurrence : verrous et isolation sans le jargon

Commencez avec des contraintes intégrées
Générez schéma, contraintes et handlers ensemble pour rendre les écritures partielles plus difficiles.

La concurrence, c'est juste deux choses qui se passent en même temps. Imaginez deux clients qui essaient d'acheter le dernier billet de concert. Les deux écrans affichent "1 restant", les deux cliquent sur Payer, et maintenant votre appli doit décider qui l'obtient.

Sans protection, les deux requêtes peuvent lire la même valeur et écrire une mise à jour. C'est ainsi que l'on se retrouve avec un stock négatif, des réservations dupliquées ou un paiement sans commande.

Les verrous de ligne sont la garde‑fou la plus simple. Vous bloquez la ligne spécifique que vous allez modifier, effectuez vos vérifications, puis la mettez à jour. Les autres transactions qui touchent la même ligne doivent attendre que vous commitiez ou fassiez rollback, ce qui empêche les mises à jour doubles.

Un motif courant : démarrer une transaction, sélectionner la ligne d'inventaire avec FOR UPDATE, vérifier qu'il y a du stock, la décrémenter, puis insérer la commande. Cela "retient la porte" pendant que vous terminez les étapes critiques.

Les niveaux d'isolation contrôlent combien d'anomalies vous tolérez quand des transactions concurrentes s'exécutent. Le compromis est généralement sécurité vs rapidité :

  • Read Committed (par défaut) : rapide, mais vous pouvez voir des changements commités par d'autres entre les instructions.
  • Repeatable Read : votre transaction voit un snapshot stable, bon pour des lectures consistantes, peut nécessiter plus de reprises.
  • Serializable : sécurité la plus forte, Postgres peut avorter une transaction pour garder l'illusion qu'elles se sont exécutées une à une.

Gardez les verrous courts. Si une transaction reste ouverte pendant que vous appelez une API externe ou attendez une action utilisateur, vous créerez des attentes longues et des timeouts. Préférez un chemin d'échec clair : définissez un lock_timeout, attrapez l'erreur et renvoyez "merci de réessayer" plutôt que de laisser les requêtes bloquer.

Si vous devez faire du travail hors base (comme débiter une carte), scindez le workflow : réservez rapidement, committez, faites la partie lente, puis finalisez avec une autre courte transaction.

Reprises qui n'engendrent pas de doublons

Les reprises sont normales dans les applications autour de Postgres. Une requête peut échouer même si votre code est correct : deadlocks, timeouts de statement, coupures réseau brèves ou erreur de sérialisation sous un niveau d'isolation élevé. Si vous relancez simplement le même handler, vous risquez de créer une seconde commande, débiter deux fois ou insérer des lignes d'"événement" en double.

La solution est l'idempotence : l'opération doit être sûre à exécuter deux fois avec la même entrée. La base doit être capable de reconnaître "c'est la même requête" et répondre de façon cohérente.

Un motif pratique consiste à joindre une clé d'idempotence (souvent un request_id généré côté client) à chaque workflow multi‑étapes et à la stocker sur l'enregistrement principal, puis à ajouter une contrainte unique sur cette clé.

Par exemple : au checkout, générez request_id quand l'utilisateur clique sur Payer, puis insérez la commande avec ce request_id. Si une reprise survient, la seconde tentative heurte la contrainte unique et vous renvoyez la commande existante au lieu d'en créer une nouvelle.

Ce qui compte généralement :

  • Utilisez une contrainte unique sur (request_id) ou (user_id, request_id) pour bloquer les doublons.
  • Quand la contrainte est violée, récupérez la ligne existante et renvoyez le même résultat.
  • Faites en sorte que les effets secondaires suivent la même règle : une seule intention de paiement par commande, un seul événement "commande confirmée" par commande.
  • Loggez le request_id pour que le support puisse retracer ce qui s'est passé.

Gardez la boucle de reprise en dehors de la transaction. Chaque tentative doit démarrer une nouvelle transaction et réexécuter l'unité de travail depuis le début. Retenter à l'intérieur d'une transaction échouée ne sert à rien car Postgres marque la transaction comme abortée.

Un petit exemple : votre appli a essayé de créer une commande et de réserver du stock, mais a timeouté juste après le COMMIT. Le client relance. Avec une clé d'idempotence, la seconde requête renvoie la commande déjà créée et évite une seconde réservation au lieu de doubler le travail.

Utilisez la base pour faire respecter les règles, pas seulement votre code

Transformer les étapes en plan
Utilisez Planning Mode pour cartographier étapes, invariants et chemins d'échec avant d'écrire le SQL.

Les transactions gardent un workflow multi‑étapes uni, mais elles ne rendent pas automatiquement les données correctes. Un moyen puissant d'éviter les conséquences des écritures partielles est de rendre les états "incorrects" difficiles ou impossibles au niveau de la base, même si un bug s'infiltre dans le code applicatif.

Commencez par des rails de sécurité de base. Les clés étrangères s'assurent que les références sont réelles (une ligne de commande ne peut pas pointer vers une commande manquante). NOT NULL empêche les lignes incomplètes. Les contraintes CHECK rejettent des valeurs absurdes (par exemple quantity > 0, total_cents >= 0). Ces règles s'exécutent à chaque écriture, quel que soit le service ou le script qui touche la base.

Pour les workflows plus longs, modélisez explicitement les changements d'état. Au lieu de plusieurs flags booléens, utilisez une colonne status unique (pending, paid, shipped, canceled) et n'autorisez que des transitions valides. Vous pouvez faire respecter cela avec des contraintes ou des triggers afin que la base refuse des sauts illégaux comme shipped -> pending.

L'unicité est une autre forme de correction. Ajoutez des contraintes uniques là où les doublons casseraient votre workflow : order_number, invoice_number ou une idempotency_key utilisée pour les reprises. Alors, si votre appli relance la même requête, Postgres bloque la deuxième insertion et vous pouvez revenir "déjà traité" au lieu de créer une seconde commande.

Quand vous avez besoin de traçabilité, stockez‑la explicitement. Une table d'audit (ou d'historique) qui enregistre qui a changé quoi et quand transforme les "mises à jour mystérieuses" en faits que vous pouvez interroger lors d'incidents.

Erreurs courantes qui causent des écritures partielles

La plupart des écritures partielles ne viennent pas d'un "mauvais SQL". Elles proviennent de décisions de workflow qui rendent facile la validation d'une moitié de l'histoire.

Les pièges rencontrés en production

  • Faire du travail externe lent pendant que la transaction est ouverte. Appeler un prestataire de paiement, envoyer un e‑mail ou téléverser un fichier dans la transaction maintient des verrous ouverts plus longtemps que nécessaire. Si l'API est lente ou timeoute, d'autres utilisateurs se retrouvent en file d'attente derrière votre transaction ouverte.
  • Lire en dehors de la transaction, puis écrire plus tard. Exemple : vous récupérez le solde d'un utilisateur, l'affichez, puis plus tard vous débitez à partir de cette valeur obsolète. Une autre session a peut‑être modifié le solde entre‑temps.
  • Attraper une erreur mais committer quand même quelque chose. Un schéma courant est "try étape 1, try étape 2, loguer l'erreur, renvoyer succès quand même." Si le code atteint COMMIT après un échec, vous avez délibérément rendu la base incohérente.
  • Mettre à jour des tables dans des ordres différents selon les chemins de code. Si une requête met à jour accounts puis orders, mais qu'une autre fait l'inverse, vous augmentez le risque de deadlocks sous charge.
  • Garder des transactions ouvertes trop longtemps. Les transactions longues peuvent bloquer les écritures, retarder le vacuum et créer des timeouts déroutants.

Un exemple concret : au checkout, vous réservez du stock, créez une commande, puis débitez une carte. Si vous débitez la carte à l'intérieur de la même transaction, vous pouvez maintenir un verrou sur le stock en attendant le réseau. Si le débit réussit mais que votre transaction fait ensuite rollback, vous avez débité le client sans commande.

Un schéma plus sûr : concentrez la transaction sur l'état en base (réserver le stock, créer la commande, enregistrer un paiement en attente), committez, appelez ensuite l'API externe, puis écrivez le résultat dans une nouvelle courte transaction. Beaucoup d'équipes implémentent cela avec un statut pending simple et un job en arrière‑plan.

Checklist rapide pour les opérations tout‑ou‑rien

Quand un workflow a plusieurs étapes (insert, update, charge, envoi), l'objectif est simple : soit tout est enregistré, soit rien.

Bornes de transaction

Mettez toutes les écritures nécessaires dans une seule transaction. Si une étape échoue, faites rollback et laissez les données telles qu'elles étaient.

Rendez la condition de succès explicite. Par exemple : "La commande est créée, le stock est réservé et le statut du paiement est enregistré." Tout le reste doit faire échouer la transaction.

  • Toutes les écritures requises se font dans un seul bloc BEGIN ... COMMIT.
  • Il y a un état fini clair dans la base (pas seulement en mémoire applicative).
  • Toute erreur mène à ROLLBACK, et l'appelant reçoit un résultat d'échec clair.

Rails de sécurité (pour que les reprises ne fassent pas de dégâts)

Supposez qu'une même requête peut être relancée. La base doit vous aider à appliquer des règles "une seule fois".

  • Appuyez les actions "une seule fois" avec des contraintes uniques (une ligne de paiement par commande, ou une réservation unique par article et commande).
  • Rendez les reprises sûres et reproductibles (même entrée = même état final, pas de doublons).

Gardez les transactions courtes

Faites le minimum à l'intérieur de la transaction et évitez d'attendre des appels réseau tout en tenant des verrous.

  • Gardez les transactions courtes et définissez un timeout pour qu'elles ne restent pas bloquées.
  • Faites le travail lent (appel à un prestataire) en dehors de la transaction, puis enregistrez le résultat dans une nouvelle transaction courte.

Observer les échecs

Si vous ne voyez pas où ça casse, vous resterez à deviner.

  • Loggez l'étape du workflow et un request id pour chaque échec.
  • Surveillez les taux de rollback et les timeouts de verrou pour détecter tôt les risques d'écriture partielle.

Exemple : un flux de checkout qui reste cohérent en cas d'échec

Implémenter le wrapper de transaction
Lancez une API Go avec Postgres et implémentez des transactions courtes avec des chemins d'erreur clairs.

Un checkout comporte plusieurs étapes qui doivent évoluer ensemble : créer la commande, réserver le stock, enregistrer la tentative de paiement, puis marquer le statut de la commande.

Imaginez qu'un utilisateur clique sur Acheter pour 1 article.

Un flux sûr (le travail en DB est une unité)

Dans une seule transaction, effectuez uniquement les changements en base :

  • Insérez une ligne orders avec le statut pending_payment.
  • Réservez le stock (par exemple décrémentez inventory.available ou créez une ligne reservations).
  • Insérez une ligne payment_intents avec une idempotency_key fournie par le client (unique).
  • Insérez une ligne outbox comme "order_created".

Si une instruction échoue (rupture de stock, violation de contrainte, plantage), Postgres rollbackera toute la transaction. Vous n'obtenez pas une commande sans réservation, ni une réservation sans commande.

Et si le paiement échoue à mi‑parcours ?

Le fournisseur de paiement est hors de la base, traitez‑le comme une étape séparée.

Si l'appel au fournisseur échoue avant votre commit, annulez la transaction et rien n'est écrit. Si l'appel échoue après votre commit, lancez une nouvelle transaction qui marque la tentative de paiement comme échouée, libère la réservation et met le statut de la commande à canceled.

Reprendre sans créer une seconde commande

Demandez au client d'envoyer une idempotency_key par tentative de checkout. Faites‑la respecter par un index unique sur payment_intents(idempotency_key) (ou sur orders si vous préférez). À la reprise, votre code recherche les lignes existantes et poursuit au lieu d'insérer une nouvelle commande.

E‑mails et notifications

N'envoyez pas d'e‑mails dans la transaction. Écrivez un enregistrement outbox dans la même transaction, puis laissez un worker l'envoyer après le commit. Ainsi vous n'envoyez jamais d'e‑mail pour une commande qui a été rollbackée.

Prochaines étapes : appliquez cela à un workflow cette semaine

Choisissez un workflow qui touche plus d'une table : signup + envoi de bienvenue, checkout + inventaire, facture + écriture en ledger, ou création de projet + paramètres par défaut.

Rédigez d'abord les étapes, puis définissez les règles qui doivent toujours être vraies (vos invariants). Exemple : "Une commande est soit entièrement payée et réservée, soit non payée et non réservée. Jamais à moitié réservée." Transformez ces règles en une unité tout‑ou‑rien.

Un plan simple :

  • Listez les opérations SQL exactes dans l'ordre (lectures, insertions, mises à jour, suppressions).
  • Ajoutez d'abord les contraintes manquantes (clés uniques, clés étrangères, checks).
  • Ajoutez une clé d'idempotence pour la requête afin que les reprises ne créent pas de doublons.
  • Enveloppez les étapes dans une transaction et rendez le point de succès explicite (commit seulement quand toutes les vérifications passent).
  • Décidez à quoi ressemble une reprise sûre (même idempotency_key, même résultat).

Puis testez volontairement les cas moches. Simulez un crash après l'étape 2, un timeout juste avant le commit et un double‑submit depuis l'UI. L'objectif est d'obtenir des résultats ennuyeux : pas de lignes orphelines, pas de doubles prélèvements, pas de statuts en attente indéfiniment.

Si vous prototypez rapidement, il est utile de dessiner le workflow dans un outil de planification avant de générer handlers et schéma. Par exemple, Koder.ai (koder.ai) propose un Planning Mode et prend en charge snapshots et rollback, ce qui peut être pratique pendant que vous itérez sur les frontières de transaction et les contraintes.

Faites cela pour un workflow cette semaine. Le second ira beaucoup plus vite.

FAQ

Quand dois-je utiliser une transaction Postgres ?

Utilisez une transaction lorsqu'une action utilisateur modifie plusieurs lignes ou tables qui doivent rester cohérentes. Les exemples courants incluent le paiement, les virements entre comptes, l'inscription avec attribution de rôle et les réservations de stock.

Que fait COMMIT dans Postgres ?

Un commit rend chaque modification de la transaction permanente et visible pour les autres sessions de base de données. N'effectuez le commit qu'une fois toutes les vérifications et écritures requises réussies.

Que se passe-t-il lorsque j'exécute ROLLBACK ?

Un rollback annule la transaction et supprime ses modifications non validées. Votre code doit effectuer un rollback si une étape requise échoue, puis renvoyer une erreur que l'appelant peut gérer.

Toutes les requêtes d'une transaction doivent-elles utiliser la même connexion ?

Conservez les lectures et écritures de base de données de ce flux de travail sur la même connexion, de BEGIN jusqu'à COMMIT ou ROLLBACK. Des connexions distinctes créent des transactions distinctes.

Dois-je appeler des API de paiement ou d'e-mail dans une transaction ?

Non. Les transactions regroupent les modifications de base de données, mais elles n'annulent pas un débit de carte, un e-mail ou un appel à une API tierce. Validez d'abord l'état de votre base de données, enregistrez un événement d'outbox ou un statut en attente, puis effectuez le travail externe séparément.

Comment empêcher deux utilisateurs d'acheter le dernier article ?

Verrouillez la ligne avant de vérifier et de mettre à jour une valeur partagée, comme le stock disponible. Par exemple, sélectionnez la ligne de stock avec FOR UPDATE, vérifiez le stock, décrémentez-le et créez la commande avant d'effectuer le commit.

Comment les nouvelles tentatives peuvent-elles éviter les commandes en double ?

Attribuez à chaque requête une clé d'idempotence stable et appliquez-la avec une contrainte d'unicité. Lorsqu'une nouvelle tentative rencontre cette contrainte, chargez et renvoyez le résultat existant au lieu d'insérer une autre commande ou un autre enregistrement de paiement.

Pourquoi les nouvelles tentatives doivent-elles démarrer une nouvelle transaction ?

Recommencez depuis le début dans une nouvelle transaction. Après une erreur d'instruction, Postgres marque la transaction en cours comme annulée, elle ne peut donc pas continuer en toute sécurité avant un rollback.

Quelles contraintes de base de données aident à éviter des données incohérentes ?

Utilisez des clés étrangères pour des références valides, NOT NULL pour les champs obligatoires, des contraintes CHECK pour des valeurs valides et des contraintes d'unicité pour les enregistrements qui ne doivent exister qu'une seule fois. Ces règles protègent les données même si le code de l'application comporte un bug.

Pourquoi les transactions doivent-elles rester courtes ?

Limitez les transactions à des opérations de base de données rapides. Les transactions longues conservent des verrous, augmentent les temps d'attente et peuvent provoquer des interblocages ou des délais d'expiration, surtout lorsqu'elles attendent un appel réseau.

Related posts