Вопрос: Я написал класс операций с базой данных TDBPerate_DL, чтобы унифицировать операции с базой данных. Методы объявления начала транзакции, фиксации транзакции и отката транзакции предоставляются для вызова других классов. TDBOperate_DL = класс PRivate ADOC:TADOConnection; ADOQ:TADOQuery; isDestroyADOC:Boolean; //Уничтожить свой собственный ADOC? fIsInTrans:Boolean; //Началась ли транзакция public isCommit:Boolean; //Независимо от того, следует ли зафиксировать транзакцию, значение по умолчанию — true, если класс голосует против отправки, это false function IsInTrans:Boolean; конструктор Create(const newADOC: TADOConnection );перегрузка; конструктор Create(const ServerName,DataBaseName,UserID,PassWord:String);перегрузка; деструктор Destroy;override; процедура BeginTrans; CommitTrans; процедура RollbackTrans; процедура Execute(const sqlString:String); функция GetDataset(const sqlString:String):_Recordset; функция GetConnection:TADOConnection; процедура SetConnection(const newADOC:TADOConnection); реализация некоторых функций: процедура TDBOperate_DL.BeginTrans; ; //Начало транзакции start self.ADOC.BeginTrans; self.fIsInTrans := true;end;procedure TDBOperate_DL.CommitTrans; //Начало фиксации транзакции self.ADOC.CommitTrans; self.fIsInTrans := false;end;procedure TDBOperate_DL.RollbackTrans; //Начало транзакции отката self.ADOC.RollbackTrans ; self.fIsInTrans := false;end;функция TDBPerate_DL.IsInTrans: Boolean; //Проверяем, началась ли транзакция, start result := self.fIsInTrans;end;Напишите класс TThing для добавления, изменения или удаления записей о чем-либо в базе данных, для завершения вызовите класс TDBPerate_DL. Для удобства вызова соответствующие транзакции помещаются в класс TThing, и нет необходимости учитывать транзакцию при совершении внешних вызовов. Например: процедура Tthing.Drop(constthing:String);var sqlString:String;begin sqlString := удаленный оператор SQL; self.DBPerate.BeginTrans; // DBOperate — это частная переменная типа TDBPerate_DL, передаваемая при создании Tthing. параметры экземпляра класса. попробуйте self.DBOperate.Execute(sqlString); self.DBOperate.CommitTrans; кроме self.DBOperate.RollbackTrans; raise; end;end; Позже я написал класс TPerson для добавления, изменения или удаления информации о людях в базе данных Record. Эта же транзакция помещена в класс TPerson. Теперь, когда я хочу удалить запись о человеке, я вызываю класс TThing для удаления вещей, связанных с человеком. Возникает проблема с транзакциями: транзакции не могут быть вложенными. Если вы сначала удалите TThing, а затем повторно объявите транзакцию для удаления TPerson, если TPerson допустит ошибку, как вы сможете откатить TThing? Например: процедура Tperson.Drop(const person:String);var sqlString:String;thing:Tthing;begin sqlString := удаленный оператор SQL;thing := Tthing.Create(self.DBOperate); //DBOperate типа TDBOperate_DL; Передается как параметр. Self.DBOperate.BeginTrans; Try Thing.Drop(person); // Внутри есть транзакция, см. код выше Self.DBOperate.Execute(sqlString); кроме self.DBOperate.RollbackTrans; end;end ;Решение, двухэтапная отправка, сначала некоторые базовые знания: независимо от двухуровневой или трехуровневой системы обработка транзакций реализуется посредством двухэтапной отправки. На первом этапе каждый выполненный ресурс/запись записывается в среду транзакции (TranscationContext), а затем координатор ресурсов последовательно запрашивает успешность выполнения каждой участвующей транзакции. Если проблем нет, он переходит ко второй фазе. выполнение начинается с фиксации своих операций. Если возникает проблема с одним выполнением, координатор ресурсов уведомляет все подчиненные исполнения о необходимости отказаться от фиксации и восстановить исходное состояние данных. Что касается операции транзакции COM+, если компоненту требуется транзакция, транзакция уже началась при создании компонента. Когда компонент уничтожается, выполняется голосование транзакции. Если это корневая транзакция, транзакция фиксируется или. откатился назад. (Если компонент поддерживает объединение в пул, эти две ситуации возникают в событиях активации и сна компонента). Итак, мы определяем класс следующим образом. //Класс-предок бизнес-класса, используемый для обеспечения унифицированной поддержки транзакций TTS_DL = class Private isRootTrans:Boolean; //Если это корневая транзакция isNeedTrans:Boolean; //Требуется ли транзакция public DBOperate:TDBOperate_DL; //Класс, который управляет процедурой экземпляра базы данных SetComplete; процедура SetAbort; конструктор Create(const newDBOperate:TDBOperate_DL; NeedTrans:Boolean);//Необходим ли деструктор поддержки транзакций Destroy; override; end; Когда этот класс создается, в дополнение к передаче экземпляра класса, который управляет базой данных, передается флаг, чтобы определить, требуется ли транзакция, потому что если операция предназначена только для чтения базы данных, , нет необходимости в транзакции. Код реализации класса следующий: конструктор TTS_DL.Create(const newDBOperate: TDBOperate_DL; NeedTrans: Boolean);begin inherited Create; self.DBOperate := newDBOperate; self.isNeedTrans := NeedTrans; //Необходима ли транзакция для назначения; if self.isNeedTrans then Begin //Если это транзакция, то это не корневая транзакция, и значение isCommit в контексте транзакции остается неизменным, если self.DBOperate.isInTrans then self.isRootTrans := false else start self.DBOperate.BeginTrans //Если это корневая транзакция, запустить транзакцию self.isRootTrans := true; self.DBOperate.isCommit := true; Инициализировать флаг фиксации. Чтобы зафиксировать транзакцию, конец; конец; деструктор TTS_DL.Destroy;begin, если self.isNeedTrans, затем начать. //Если это корневая транзакция, зафиксируйте или откатите транзакцию в соответствии с результатами голосования if self.isRootTrans then start if self.DBOperate.isCommit then self.DBOperate.CommitTrans else self.DBOperate.RollbackTrans end; конец; процедура TTS_DL.SetAbort; начало self.DBOperate.isCommit: = self.DBOperate.isCommit И false; //Голосование за откат;процедура TTS_DL.SetComplete;begin self.DBOperate.isCommit := self.DBOperate.isCommit And true; //Голосование за фиксацию;Вернитесь к бизнес-классам Tthing и Tperson, на этот раз все они унаследованы от Класс TTS_DL. Tthing = class(TTS_DL); Tperson = class(TTS_DL); Код удаления Tthing должен быть следующим: . DBOperate.Execute(sqlString); self. DBOperate.SetComplete; // Голосование за исключением self. DBOperate.SetAbort; //Откат голосования поднять; end;end; Код удаления для Tperson следующий: процедура Tperson.Drop(const person:String);var sqlString:String; ; вещь: = Tthing.Create(self. DBOperate, true); //TDBOperate_DL Тип DBOperate передается в качестве параметра, true означает, что транзакция требуется. Попробуйте Thing.Drop(person); Self.DBOperate.Execute(sqlString); self.DBOperate.SetComplete; //Проголосовать за отправку, кроме self.DBOperate.SetAbort; //Откат голосования, end; //Не забудьте освободить end;end; Не забудьте сохранить единственный экземпляр рабочего класса базы данных TDBOperate_DL, используемый в программе, и не забудьте освободить экземпляр бизнес-класса. Если требуется транзакция, освободите его как можно раньше, ОК. сделанный. Первая версия имеет ограниченный уровень и нуждается в улучшении в практическом применении. Это просто способ привлечь новые идеи. Пожалуйста, приглашайте опытных героев :)