Utiliser des transactions

4D - Documentation   Français   English   German   Español   4D v11 SQL, Commandes par thèmes   4D v11 SQL, Liste alphabétique des commandes   4D v11 SQL, Constantes par thèmes   Retour   Précédent   Suivant

version 11 (Modifiée)


Les transactions sont une série de modifications effectuées à l'intérieur d'un process sur des données reliées entre elles. Une transaction n'est sauvegardée de façon définitive dans la base que si la transaction est validée. Si une transaction n'est pas complétée, parce qu'elle est annulée ou en raison d'un quelconque événement extérieur, les modifications ne sont pas sauvegardées.

Pendant une transaction, toutes les modifications effectuées sur les données de la base dans le process sont stockées localement dans un buffer temporaire. Si la transaction est acceptée avec VALIDER TRANSACTION, les changements sont sauvegardés de façon définitive. Si la transaction est annulée avec ANNULER TRANSACTION, les changements ne sont pas sauvegardés. Dans tous les cas, ni la sélection courante ni l'enregistrement courant ne sont modifiés par les commandes de gestion des transactions.

A compter de la version 11, 4D prend en charge les transactions imbriquées, c'est-à-dire les transactions sur plusieurs niveaux hiérarchiques. Le nombre de sous-transactions autorisées est illimité. La commande Niveau de la transaction permet de connaître le niveau courant de transaction dans lequel le code est exécuté.

Lorsque vous utilisez des transactions imbriquées, le résultat de chaque sous-transaction dépend de la validation ou de l'annulation de la transaction du niveau supérieur. Si la transaction supérieure est validée, les résultats des sous-transactions sont entérinés (validation ou annulation). En revanche, si la transaction supérieure est annulée, toutes les sous-transactions sont annulées, quels que soient leurs sous-résultats.

Option de compatibilité

Les transactions imbriquées pouvant générer des dysfonctionnements dans les bases développées avec des versions précédentes de 4D, il est désactivé par défaut dans les bases converties (les transactions restent limitées à un seul niveau). Si vous souhaitez bénéficier des transactions sur plusieurs niveaux dans une base convertie, vous devez l'indiquer explicitement en cochant l'option Transactions imbriquées dans la page "Application/Compatibilité" des Préférences de l'application.

Cette option n'apparaît que pour les bases de données converties. Par défaut, elle n'est pas cochée. Elle est spécique à chaque base de données. Elle n'a pas d'effet sur les transactions effectuées dans le moteur SQL de 4D. Les transactions SQL sont toujours multi-niveaux.

Exemples de transactions


L'exemple de cette section s'appuie sur la structure présentée ci-dessous. C'est une base relativement simple de facturation. Les lignes de factures sont stockées dans une table appelée [Ligne Facture], qui est reliée à la table [Factures] par une relation entre les champs [Factures]NoFacture et [Ligne Facture]NoFacture. Lorsqu'une facture est ajoutée, un numéro unique est calculé avec la commande Numerotation automatique. Le lien entre [Factures] et [Ligne Facture] est du type aller-retour automatique. L'option "Mise à jour auto dans les sous-formulaires" est cochée.

La lien entre [Ligne Facture] et [Pièces] est manuel.

Quand un utilisateur saisit une facture, les actions suivantes doivent être exécutées :

Ajouter un enregistrement dans la table [Factures].

 Ajouter plusieurs enregistrements dans la table [Ligne Facture].

Mettre à jour le champ [Pièces]Entrepôt pour chaque pièce figurant sur la facture.

En d'autres termes, vous devez sauvegarder les données liées. C'est la situation type où vous devez utiliser une transaction. Vous pourrez ainsi être certain de pouvoir soit sauvegarder tous ces enregistrements pendant l'opération, soit annuler la transaction si un enregistrement ne peut être ajouté ou mis à jour.

Si vous n'utilisez pas une transaction, vous ne pouvez pas garantir l'intégrité logique des données de votre base. Par exemple, si un enregistrement parmi ceux de la table [Pièces] est verrouillé, vous ne pourrez pas mettre à jour la quantité stockée dans le champ [Pièces]Entrepôt. Ce champ sera alors logiquement incorrect. La somme des pièces vendues et restantes dans l'entrepôt ne sera pas égale à la quantité d'origine saisie dans l'enregistrement. Vous pouvez éviter cette situation en utilisant les transactions.

Il y a plusieurs façons d'effectuer une saisie sous transaction :

(1) Vous pouvez gérer les transactions en utilisant les commandes de transaction DEBUT TRANSACTION, VALIDER TRANSACTION et ANNULER TRANSACTION. Vous pouvez par exemple écrire :

   LECTURE ECRITURE([Ligne Facture])
   LECTURE ECRITURE([Pièces])
   FORMULAIRE ENTREE([Factures];"Saisie")
   Repeter
      DEBUT TRANSACTION
      AJOUTER ENREGISTREMENT([Factures])
      Si (OK=1)
         VALIDER TRANSACTION 
      Sinon
         ANNULER TRANSACTION  
      Fin de si
   Jusque (OK=0)
   LECTURE SEULEMENT(*)

(2) Pour réduire les verrouillages des enregistrements pendant la saisie de données, vous pouvez aussi choisir de gérer les transactions à partir de la méthode du formulaire et d'accéder aux tables en LECTURE ECRITURE uniquement quand cela est nécessaire.

Vous effectuez la saisie de données en utilisant le formulaire de saisie pour [Factures], qui contient la table liée [Factures]Lignes dans un sous-formulaire. Le formulaire comporte deux boutons : bAnnuler et bOK. Aucune action ne leur est attribuée.

La boucle d'ajout devient alors :

   LECTURE ECRITURE([Ligne Facture])
   LECTURE SEULEMENT([Pièces])
   FORMULAIRE ENTREE([Factures];"Input")
   Repeter
      AJOUTER ENREGISTREMENT([Factures])
   Jusque (bOK=0)
   LECTURE SEULEMENT([Ligne Facture])

Notez que la table [Pièces] est désormais en "lecture seulement" pendant la saisie de données. L'accès en lecture/écriture ne s'active que si les données sont validées.

La transaction est ouverte dans la méthode du formulaire entrée de la table [Factures] :

   Au cas ou
      : (Evenement formulaire=Sur chargement)
         DEBUT TRANSACTION
         [Factures]NoFactures:=Numerotation automatique([Factures]NoFactures)
      Sinon
         [Factures]Total facture:=Somme([Ligne Facture]Total ligne)
   Fin de cas

Si vous cliquez sur le bouton bAnnuler, la saisie et la transaction doivent être annulées. Voici la méthode objet du bouton bAnnuler:

   Au cas ou
      : (Evenement formulaire=Sur clic)
         ANNULER TRANSACTION
         NE PAS VALIDER 
   Fin de cas

Si vous cliquez sur le bouton bOK, la saisie et la transaction doivent être acceptées. Voici la méthode objet du bouton bOK :

   Au cas ou
      : (Evenement formulaire=Sur clic)
         $NbLines:=Enregistrements trouves([Ligne Facture])
         LECTURE ECRITURE([Pièces])   ` Passer en lecture/écriture pour accéder à la table [Pièces]
         DEBUT SELECTION([Ligne Facture])   ` Commencer à la première ligne
         $ValidTrans:=Vrai  ` Tout devrait marcher
         Boucle ($Line;1;$NbLines)   ` Pour chaque ligne
            CHARGER SUR LIEN([Ligne Facture]NoPiece)
            OK:=1  ` Vous voulez continuer
            Tant que (Enregistrement verrouille([Pièces]) & (OK=1))  
                   ` Essayer d'obtenir l'enregistrement en lecture/écriture
               CONFIRMER("La pièce "+[Ligne Facture]NoPiece+" est utilisée. Vous attendez ?")
               Si (OK=1)
                  ENDORMIR PROCESS(Numero du process courant;60)
                  CHARGER ENREGISTREMENT([Pièces])
               Fin de si
            Fin tant que
            Si (OK=1)
                  ` Mettre à jour quantité dans l'entrepôt
               [Pièces]Entrepôt:=[Pièces]Entrepôt-[Ligne Facture]Quantité
               STOCKER ENREGISTREMENT([Pièces])   ` Sauvegarder l'enregistrement
            Sinon
               $Ligne:=$NbLines+1   ` Sortir de la boucle
               $ValidTrans:=Faux
            Fin de si
            ENREGISTREMENT SUIVANT([Ligne Facture])   ` Aller à la ligne suivante
         Fin de boucle
         LECTURE SEULEMENT([Pièces])   ` Mettre la table en mode lecture seulement
         Si ($ValidTrans)
            STOCKER ENREGISTREMENT([Factures])   ` Sauvegarder les enregistrements
            VALIDER TRANSACTION   ` Valider toutes les modifications de la base
         Sinon
            ANNULER TRANSACTION   ` Tout annuler
         Fin de si
         NE PAS VALIDER   ` Quitter le formulaire
   Fin de cas

Dans le code ci-dessus, quel que soit le bouton sur lequel l'utilisateur a cliqué, nous appelons la commande NE PAS VALIDER. Le nouvel enregistrement n'est pas validé par un appel à VALIDER mais par STOCKER ENREGISTREMENT. De plus, vous remarquez que STOCKER ENREGISTREMENT est appelée juste avant la commande VALIDER TRANSACTION. Ainsi, la sauvegarde de l'enregistrement [Factures] est partie intégrante de la transaction. Appeler la commande VALIDER validerait aussi l'enregistrement mais dans ce cas, la transaction serait validée avant le stockage de la facture. Autrement dit, l'enregistrement serait sauvegardé en-dehors de la transaction.

En fonction de vos besoins, personnalisez votre base à votre convenance, comme dans les exemples précédents. Dans le dernier exemple, la gestion du verrouillage des enregistrements de la table [Pièces] pourrait être plus élaborée.

Référence

ANNULER TRANSACTION, DEBUT TRANSACTION, Transaction en cours, VALIDER TRANSACTION.


4D - Documentation   Français   English   German   Español   4D v11 SQL, Commandes par thèmes   4D v11 SQL, Liste alphabétique des commandes   4D v11 SQL, Constantes par thèmes   Retour   Précédent   Suivant