線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1661
推到 Plurk!
推到 Facebook!

用MSDTC作分散式Transaction

 
mustapha.wang
資深會員


發表:89
回覆:409
積分:274
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-03-11 13:51:33 IP:218.80.xxx.xxx 未訂閱
当你要把对两个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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-03-11 14:24:12 IP:218.80.xxx.xxx 未訂閱
继续下去有个问题请教: 像Com+,我们在写com+元件时,自己放了TADOConnection,可是COm+不会知道有个Borland的TADOConnection,应该是在ole db的底层拦截到的ole db的session,然后把它加入到DTC的transaction里,请问,如何拦截?又如何区分该不该把某个session加到transaction或加到一个新的transaction,因为com+元件可能不需要transaction或者需要新的transaction。     久病成良医--多试 千人之诺诺,不如一士之谔谔--兼听
------
江上何人初见月,江月何年初照人
系統時間:2024-05-06 1:01:35
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!