Question : J'ai écrit une classe d'opérations de base de données TDBPerate_DL pour unifier les opérations sur la base de données. Des méthodes permettant de déclarer le début d'une transaction, de valider une transaction et d'annuler une transaction sont fournies pour que d'autres classes puissent les appeler. TDBOperate_DL = class PRivate ADOC:TADOConnection; ADOQ:TADOQuery; isDestroyADOC:Boolean; //Détruire votre propre ADOC ? fIsInTrans:Boolean; //Si la transaction a démarré public isCommit:Boolean; //Si la transaction doit être validée, la valeur par défaut est vraie, si une classe vote contre la soumission, c'est faux function IsInTrans:Boolean constructor Create(const newADOC: TADOConnection );surcharge; constructeur Create(const ServerName,DataBaseName,UserID,PassWord:String);surcharge;destructeur Destroy;procédure de remplacement BeginTrans; CommitTrans; procédure RollbackTrans; procédure Execute(const sqlString:String); fonction GetDataset(const sqlString:String):_Recordset; fonction GetConnection:TADOConnection; procédure SetConnection(const newADOC:TADOConnection end); ; //Démarrer la transaction start self.ADOC.BeginTrans; self.fIsInTrans := true;end;procedure TDBOperate_DL.CommitTrans; // Début de la transaction de validation self.ADOC.CommitTrans; self.fIsInTrans := false;end;procedure TDBOperate_DL.RollbackTrans; // Début de la transaction de restauration self.ADOC.RollbackTrans ; self.fIsInTrans := false;end;function TDBPerate_DL.IsInTrans: Boolean; //Vérifiez si la transaction a commencé start result := self.fIsInTrans;end;Écrivez une classe TThing pour ajouter, modifier ou supprimer des enregistrements sur quelque chose dans la base de données, appelez la classe TDBPerate_DL pour terminer. Pour faciliter les appels, les transactions pertinentes sont placées dans la classe TThing et il n'est pas nécessaire de prendre en compte la transaction lors des appels externes. Par exemple : procédure Tthing.Drop(const thing:String);var sqlString:String;begin sqlString := instruction SQL supprimée; self.DBPerate.BeginTrans; // DBOperate est une variable privée de type TDBPerate_DL, transmise lors de la création d'un Tthing. paramètres d'instance de classe. essayez self.DBOperate.Execute(sqlString); self.DBOperate.CommitTrans; sauf self.DBOperate.RollbackTrans; raise end;end; Plus tard, j'ai écrit une classe TPerson pour ajouter, modifier ou supprimer des informations sur les personnes dans la base de données. La même transaction est placée dans la classe TPerson. Désormais, lorsque je souhaite supprimer l'enregistrement d'une personne, j'appelle la classe TThing pour supprimer les éléments liés à la personne. Un problème de transaction survient : les transactions ne peuvent pas être imbriquées. Si vous supprimez d'abord TThing, puis déclarez à nouveau la transaction pour supprimer TPerson, si TPerson fait une erreur, comment pouvez-vous restaurer TThing ? Par exemple : procédure Tperson.Drop(const person:String);var sqlString:String; thing:Tthing;begin sqlString := instruction SQL supprimée ; thing := Tthing.Create(self.DBOperate); //Le DBOperate de type TDBOperate_DL ; est transmis en tant que paramètre. Self.DBOperate.BeginTrans; Try Thing.Drop(person); //Il y a une transaction à l'intérieur, voir le code ci-dessus Self.DBOperate.Execute(sqlString); self.DBOperate.CommitTrans; end;end ;Solution, soumission en deux phases, d'abord quelques connaissances de base : quel que soit le système à deux ou trois niveaux, le traitement des transactions est réalisé via une soumission en deux phases. Dans la première phase, chaque ressource/enregistrement exécuté est écrit dans l'environnement de transaction (TranscationContext), puis le coordinateur de ressources demande séquentiellement si l'exécution de chaque transaction participante est réussie. S'il n'y a aucun problème, il entre dans la deuxième phase. l’exécution commence par la validation de ses opérations. S'il y a un problème avec une exécution, le coordinateur de ressources demande à toutes les exécutions subordonnées d'abandonner Commit et de restaurer l'état d'origine des données. En ce qui concerne l'opération de transaction de COM+, si un composant nécessite une transaction, la transaction a déjà commencé lorsque le composant est créé. Lorsque le composant est détruit, un vote de transaction est effectué. S'il s'agit d'une transaction racine, la transaction est validée ou. reculé. (Si le composant prend en charge le pooling, ces deux situations se produisent dans les événements d'activation du composant et de veille). Nous définissons donc une classe comme suit. //Classe ancêtre de la classe affaires, utilisée pour fournir une prise en charge unifiée des transactions TTS_DL = class private isRootTrans:Boolean; //S'il s'agit d'une transaction racine isNeedTrans:Boolean; //Si une transaction est requise public DBOperate:TDBOperate_DL //Class that exploite la procédure d'instance de base de données SetComplete ; procédure SetAbort ; constructeur Create(const newDBOperate:TDBOperate_DL; needTrans:Boolean);//Si un destructeur de support de transaction est requis Destroy; override; end; Lorsque cette classe est créée, en plus de transmettre l'instance de la classe qui exploite la base de données, un indicateur est transmis pour indiquer si une transaction est requise, car s'il s'agit uniquement d'une opération de lecture du base de données, aucune transaction n’est nécessaire. Le code d'implémentation de la classe est le suivant : constructor TTS_DL.Create(const newDBOperate: TDBOperate_DL; needTrans: Boolean);begin generic Create; self.DBOperate := self.isNeedTrans := needTrans //Si l'affectation nécessite une transaction si self. .isNeedTrans commence alors //S'il est dans une transaction, ce n'est pas la transaction racine, et la valeur de isCommit dans le contexte de la transaction reste inchangée si self.DBOperate.isInTrans then self.isRootTrans := false else start self.DBOperate.BeginTrans; //S'il s'agit de la transaction racine, démarrez la transaction self.isRootTrans := true; Initialiser l'indicateur de validation Pour valider la transaction end;end;end;destructor TTS_DL.Destroy;begin if self.isNeedTrans then begin // S'il s'agit d'une transaction racine, validez ou annulez la transaction en fonction des résultats du vote if self.isRootTrans then start if self.DBOperate.isCommit then self.DBOperate.CommitTrans else self.DBOperate.RollbackTrans end hérité; fin;procédure TTS_DL.SetAbort;begin self.DBOperate.isCommit := self.DBOperate.isCommit Et false; //Vote pour rollbackend;procedure TTS_DL.SetComplete;begin self.DBOperate.isCommit := self.DBOperate.isCommit Et true; //Vote pour commitend;Retour aux classes métier Tthing et Tperson, cette fois Tous sont hérités de Classe TTS_DL. Tthing = class(TTS_DL); Tperson = class(TTS_DL); Le code de suppression de Tthing doit être le suivant : procédure Tthing.Drop(const thing:String);var sqlString:String;begin sqlString := instruction SQL supprimée ; . DBOperate.Execute(sqlString); self.DBOperate.SetComplete; //Soumission de vote sauf self. DBOperate.SetAbort; //Vote rollback raise; end;end; Le code de suppression de Tperson est le suivant : procédure Tperson.Drop(const person:String);var sqlString:String;begin sqlString := instruction SQL supprimée; := Tthing.Create(self. DBOperate,true); // Le type TDBOperate_DL DBOperate est transmis en paramètre, true signifie qu'une transaction est requise. Essayez Try Thing.Drop(person); Self.DBOperate.Execute(sqlString); self.DBOperate.SetComplete; // Soumission du vote sauf self.SetAbort; //N'oubliez pas de libérer end;end;N'oubliez pas de conserver la seule instance de la classe de base de données d'exploitation TDBOperate_DL utilisée dans le programme, et n'oubliez pas de libérer l'instance de classe affaires si une transaction est requise, libérez-la le plus tôt possible, OK, fait. La première version a un niveau limité et doit être améliorée dans les applications pratiques. C'est juste un moyen d'attirer de nouvelles idées. Veuillez demander à des héros expérimentés de contribuer :)