用MSDTC作分散式Transaction |
|
mustapha.wang
資深會員 發表:89 回覆:409 積分:274 註冊:2002-03-13 發送簡訊給我 |
当你要把对两个database的资料修改放在一个Transaction处理的时候,如果这样写,是可能出问题的:
procedure TForm1.Button3Click(Sender: TObject); begin ADOConnection1.Open; ADOConnection1.BeginTrans; ADOConnection2.Open; ADOConnection2.BeginTrans; try ADOQuery1.Open; ADOQuery1.Edit; ADOQuery1.FieldByName('CurrentValue').AsInteger:= ADOQuery1.FieldByName('CurrentValue').AsInteger+10; ADOQuery1.Post; ADOConnection1.CommitTrans; ADOQuery2.Open; ADOQuery2.Edit; ADOQuery2.FieldByName('OrderDate').asDateTime:= ADOQuery2.FieldByName('OrderDate').asDateTime+1; ADOQuery2.Post; // Raise Exception.Create('Error'); ADOConnection2.CommitTrans; except if ADOConnection2.InTransaction then ADOConnection2.RollbackTrans; if ADOConnection1.InTransaction then ADOConnection1.RollbackTrans; ADOQuery1.Close; ADOQuery1.Open; ADOQuery2.Close; ADOQuery2.Open; Raise; end; end;因为ADOConnection1.CommitTrans;成功后,后面的某句执行失败,再调用ADOConnection1.RollbackTrans;也不起作用了。 跨资料库的分散式transaction必须借助专门支援分散式transaction的工具,如MSDTC,下面是我找了很多资料,反复试验才获得点点经验(为了方便被搜索到,代码也短,就不附文件直接贴出了): unit DTCTransaction; interface uses SysUtils,Windows,OleDB,ADODB,ADOInt,COmObj; const CLSID_MSDASQL :TGUID='{C8B522CB-5CF3-11CE-ADE5-00AA0044773D}'; //oledb for ODBC CLSID_SQLOLEDB:TGUID='{0C7FF16C-38E3-11D0-97AB-00C04FC2AD98}'; //oledb for sql server function DTCTransactionStart:ITransaction; procedure DTCTransactionCommit(ATransaction:ITransaction); procedure DTCTransactionRollback(ATransaction:ITransaction); procedure JoinSessionIntoTransaction(AConnectionArray:array of TADOConnection;ATransaction:ITransaction); procedure UnJoinSession(AConnectionArray:array of TADOConnection); implementation function DtcGetTransactionManager( hostName:PChar; tmName:PChar; iid:Pointer;//pointer of TGUID; dwReserved1:DWord; wReserved2:Word; pvReserved:Pointer; out txnDispenser:ITransactionDispenser):HResult;cdecl;external 'xolehlp.dll'; const TransactionISOLATIONLEVEL=ISOLATIONLEVEL_SERIALIZABLE; function DTCTransactionStart:ITransaction; var ID:ITransactionDispenser; begin Result:=nil; OLECheck(DtcGetTransactionManager( nil, nil, @IID_ITransactionDispenser, 0,0, nil, ID)); OLECheck(ID.BeginTransaction(nil, TransactionISOLATIONLEVEL, ISOFLAG_RETAIN_DONTCARE,nil,Result)); end; procedure DTCTransactionCommit(ATransaction:ITransaction); begin OLECheck(ATransaction.Commit(false,0,0)); end; procedure DTCTransactionRollback(ATransaction:ITransaction); var B:BOID; begin OLECheck(ATransaction.Abort(@B,false,false)); end; procedure JoinSessionIntoTransaction(AConnectionArray:array of TADOConnection;ATransaction:ITransaction); var ICC:ADOConnectionConstruction; ISP:IInterface; ITJ:ITransactionJoin; i:integer; begin for i:=Low(AConnectionArray) to High(AConnectionArray) do begin if not AConnectionArray[i].Connected then AConnectionArray[i].Open; OLECheck(AConnectionArray[i].ConnectionObject.QueryInterface(IID_ADOConnectionConstruction,ICC)); ISP:=ICC.Get_Session; OLECheck(ISP.QueryInterface(IID_ITransactionJoin,ITJ)); OLECheck(ITJ.JoinTransaction(ATransaction,TransactionISOLATIONLEVEL,0,nil)); end; end; procedure UnJoinSession(AConnectionArray:array of TADOConnection); var ICC:ADOConnectionConstruction; ISP:IInterface; ITJ:ITransactionJoin; i:integer; begin for i:=Low(AConnectionArray) to High(AConnectionArray) do begin if AConnectionArray[i].Connected then begin OLECheck(AConnectionArray[i].ConnectionObject.QueryInterface(IID_ADOConnectionConstruction,ICC)); ISP:=ICC.Get_Session; OLECheck(ISP.QueryInterface(IID_ITransactionJoin,ITJ)); OLECheck(ITJ.JoinTransaction(nil,0,0,nil)); end; end; end; end. procedure TForm1.Button1Click(Sender: TObject); var IT:ITransaction; begin IT:=DTCTransactionStart; JoinSessionIntoTransaction([ADOConnection1,ADOConnection2],IT); try try ADOQuery1.Open; ADOQuery1.Edit; ADOQuery1.FieldByName('CurrentValue').AsInteger:= ADOQuery1.FieldByName('CurrentValue').AsInteger+10; ADOQuery1.Post; ADOQuery2.Open; ADOQuery2.Edit; ADOQuery2.FieldByName('OrderDate').asDateTime:= ADOQuery2.FieldByName('OrderDate').asDateTime+1; ADOQuery2.Post; // Raise Exception.Create('Error'); DTCTransactionCommit(IT); except DTCTransactionRollback(IT); Raise; end; finally UnJoinSession([ADOConnection1,ADOConnection2]); ADOQuery1.Close; ADOQuery1.Open; ADOQuery2.Close; ADOQuery2.Open; end; end;久病成良医--多试 千人之诺诺,不如一士之谔谔--兼听
------
江上何人初见月,江月何年初照人 |
mustapha.wang
資深會員 發表:89 回覆:409 積分:274 註冊:2002-03-13 發送簡訊給我 |
继续下去有个问题请教:
像Com+,我们在写com+元件时,自己放了TADOConnection,可是COm+不会知道有个Borland的TADOConnection,应该是在ole db的底层拦截到的ole db的session,然后把它加入到DTC的transaction里,请问,如何拦截?又如何区分该不该把某个session加到transaction或加到一个新的transaction,因为com+元件可能不需要transaction或者需要新的transaction。
久病成良医--多试
千人之诺诺,不如一士之谔谔--兼听
------
江上何人初见月,江月何年初照人 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |