ServiceObject的TransactionMode有三個取值:不需要交易,需要交易,需要新的交易。ServiceObject的方法被調用時會建立一個TTransactionContext,並隨著子元件,子子元件的調用傳遞,子元件,子子元件只是對這個Transaction投票,是需要Commit還是Rollback,根元件根據最後結果來決定最後該Commit還是Rollback。
TCustomServiceObject=class(TObject)<br /> private<br /> FServiceName:string;<br /> FDataObjectCreated:Boolean;<br />//自己使用,每個ServiceObject按需要擁有IDBService<br /> FDataObject:TCustomServiceObject;<br /> FContext:TTransactionContext;<br /> FContextCreated:Boolean;<br /> function GetContext: TTransactionContext;<br /> procedure LeaveActivity;<br /> private<br /> FStatus:TServiceObjectStatus;<br /> FIsLocked:Boolean;<br /> FThreadHandle:THandle;<br /> FTimeout:integer;<br /> procedure SetStatus(const Value: TServiceObjectStatus);<br /> protected<br /> procedure Activate;virtual;<br /> procedure Deactivate;virtual;<br /> function IsCanBePooled:Boolean;virtual;<br /> function GetTransactionMode:TServiceTransactionMode;virtual;<br /> function GetDataObject: TCustomServiceObject;virtual;<br /> function GetDataService: IDBService;virtual;<br /> function GetIsInTransaction: Boolean;virtual;<br /> function CallMethod(const AMethodName: string; const AParams: OLEVariant;<br /> const AAsyncCallContent:TASyncCallContent;<br /> const AClientContent:TClientContent):OLEVariant;virtual;<br /> public<br /> constructor Create(AServiceName:string);virtual;<br /> destructor Destroy;override;<br /> //調用自己的某個函數<br /> function Call(const AMethodName: string; const AParams: OLEVariant;<br /> const AASyncCallContent:TASyncCallContent=nil;<br /> const AClientContent:TClientContent=nil): OLEVariant;virtual;<br /> //調用其它的元件<br /> function CallOther(const AServiceName,AMethodName:string;<br /> const AParams:OLEVariant;<br /> const AASyncCallContent:TASyncCallContent=nil;<br /> const AClientContent:TClientContent=nil):OLEVariant;virtual;<br /> //在activity線程中獲得一個服務元件<br /> function BeginUseServiceObject(const AServiceName:string;const AServiceObjectStub:integer=-1):TCustomServiceObject;virtual;<br /> //結束activity中的物件使用<br /> procedure EndUseSerivceObject(AService:TCustomServiceObject);virtual;<br /> //投票確認activity的交易<br /> procedure VoteCommitTransaction;virtual;<br /> //投票拒絕activity的交易<br /> procedure VoteRollbackTransaction;virtual;<br /> //某個函數在調用時是否需要記錄日誌<br /> function IsMethodNeedLog(AMethodName:string):Boolean;virtual;</p><p> property DataObject:TCustomServiceObject read GetDataObject;<br /> property DataService:IDBService read GetDataService;<br /> property Context:TTransactionContext read GetContext;<br /> property IsInTransaction:Boolean read GetIsInTransaction;<br /> property Status:TServiceObjectStatus read FStatus write SetStatus;<br /> end;</p><p>function TCustomServiceObject.Call(const AMethodName: string;<br /> const AParams: OLEVariant;<br /> const AASyncCallContent:TASyncCallContent=nil;<br /> const AClientContent:TClientContent=nil): OLEVariant;<br />const<br /> UseDTCTransaction=false;<br />var<br />//單個Connection執行“BEGIN DISTRIBUTED TRANSACTION”並不能將多個Connection納入分散式交易<br /> IsRoot:Boolean;<br /> procedure CheckTransactionStart;<br /> begin<br /> case GetTransactionMode of<br /> tmNeedNew:<br /> begin<br />//開始新的activity,這個交易沿新的activity傳遞<br /> if not FContextCreated then FContext:=nil;<br />//不使用activity傳下來的DataOject<br /> if not FDataObjectCreated then FDataObject:=nil;<br /> if not IsInTransaction then<br /> begin<br /> if UseDTCTransaction then<br /> begin<br /> Context.FTransaction:=DTCTransaction.DTCTransactionStart;<br /> DataService.JoinDistributeTransaction(Context.FTransaction);<br /> end<br /> else<br /> DataService.StartTransaction;<br /> end;<br /> end;<br /> tmNeed:<br /> begin<br /> if not IsInTransaction then<br /> begin //根元件啟動交易<br /> IsRoot:=true;<br /> if UseDTCTransaction then<br /> begin<br /> Context.FTransaction:=DTCTransaction.DTCTransactionStart;<br /> DataService.JoinDistributeTransaction(Context.FTransaction);<br /> end<br /> else<br /> DataService.StartTransaction;<br /> end;<br /> end;<br /> end;<br /> end;</p><p> procedure CheckTransactionCommit;<br /> begin<br /> if GetTransactionMode=tmNeedNew then<br /> begin<br /> if UseDTCTransaction then<br /> DTCTransaction.DTCTransactionCommit(Context.FTransaction)<br /> else<br /> DataService.CommitTransaction;<br /> end<br /> else if IsRoot then<br /> begin<br />//根元件根據activity的投票結果,決定確認交易還是復原交易<br /> if Context.FVoteTransactionRollbacked then<br /> begin<br /> if UseDTCTransaction then<br /> DTCTransaction.DTCTransactionRollback(Context.FTransaction)<br /> else<br /> DataService.RollbackTransaction;<br /> end<br /> else<br /> begin<br /> if UseDTCTransaction then<br /> DTCTransaction.DTCTransactionCommit(Context.FTransaction)<br /> else<br /> DataService.CommitTransaction;<br /> end;<br /> end;<br />//投票確認activity交易<br /> VoteCommitTransaction;<br /> end;</p><p> procedure CheckTransactionRollback;<br /> begin<br /> if GetTransactionMode=tmNeedNew then<br /> begin<br /> if IsInTransaction then<br /> if UseDTCTransaction then<br /> DTCTransaction.DTCTransactionCommit(Context.FTransaction)<br /> else<br /> DataService.RollbackTransaction;<br /> end<br /> else if IsRoot then<br /> begin<br /> if IsInTransaction then<br /> if UseDTCTransaction then<br /> DTCTransaction.DTCTransactionCommit(Context.FTransaction)<br /> else<br /> DataService.RollbackTransaction;<br /> end;<br />//表決復原activity的交易<br /> VoteRollbackTransaction;<br /> end;</p><p> procedure CheckClearTransaction;<br /> begin<br /> if (GetTransactionMode=tmNeedNew) or IsRoot then<br /> begin<br /> if IsInTransaction then<br /> if UseDTCTransaction then<br /> DataService.UnJoinDistributeTransaction;<br /> ConText.FTransaction:=nil;<br /> ConText.FVoteTransactionRollbacked:=false;<br /> end;<br /> end;<br />var<br /> ATime:TDateTime;<br />begin<br /> Result:=null;<br /> ATime:=Now;<br /> if ServiceLog<>nil then<br /> ServiceLog.ServiceObjectBeforeMethodCalled(FServiceName,AMethodName);<br /> IsRoot:=false;<br /> try<br /> try<br /> CheckTransactionStart;<br /> Result:=CallMethod(AMethodName,AParams,AAsyncCallContent,AClientContent);<br /> CheckTransactionCommit;<br /> except<br /> CheckTransactionRollback;<br /> Raise;<br /> end;<br /> finally<br /> CheckClearTransaction;<br /> if ServiceLog<>nil then<br /> ServiceLog.ServiceObjectAfterMethodCalled(<br /> FServiceName,AMethodName,Round((Now-ATime)*86400000));<br /> end;<br />end;
如果是多個資料庫的分散式Transaction,需要調用MSDTC來控制。
unit DTCTransaction;</p><p>interface<br />uses<br /> SysUtils,OleDB,ComObj,Windows;</p><p> function DTCTransactionStart:ITransaction;<br /> procedure DTCTransactionCommit(ATransaction:ITransaction);<br /> procedure DTCTransactionRollback(ATransaction:ITransaction);</p><p>const<br /> TransactionISOLATIONLEVEL=ISOLATIONLEVEL_SERIALIZABLE;<br /> CLSID_MSDASQL :TGUID='{C8B522CB-5CF3-11CE-ADE5-00AA0044773D}'; //oledb for ODBC<br /> CLSID_SQLOLEDB :TGUID='{0C7FF16C-38E3-11D0-97AB-00C04FC2AD98}'; //oledb for sql server</p><p>implementation</p><p> function DtcGetTransactionManager(<br /> hostName:PChar;<br /> tmName:PChar;<br /> iid:Pointer;//pointer of TGUID;<br /> dwReserved1:DWord;<br /> wReserved2:Word;<br /> pvReserved:Pointer;<br /> out txnDispenser:ITransactionDispenser):HResult;cdecl;external 'xolehlp.dll';</p><p>function DTCTransactionStart:ITransaction;<br />var<br /> ID:ITransactionDispenser;<br />begin<br /> Result:=nil;<br /> OLECheck(DtcGetTransactionManager(<br /> nil,<br /> nil,<br /> @IID_ITransactionDispenser,<br /> 0,0,<br /> nil,<br /> ID));</p><p> OLECheck(ID.BeginTransaction(nil,<br /> TransactionISOLATIONLEVEL,<br /> ISOFLAG_RETAIN_DONTCARE,nil,Result));<br />end;</p><p>procedure DTCTransactionCommit(ATransaction:ITransaction);<br />begin<br /> OLECheck(ATransaction.Commit(false,0,0));<br />end;</p><p>procedure DTCTransactionRollback(ATransaction:ITransaction);<br />var<br /> B:BOID;<br />begin<br /> OLECheck(ATransaction.Abort(@B,false,false));<br />end;</p><p>end.