我公司有个软件采用用的三层结构,其中间层采用com+组件实现,改组件的接口如下
Type
     IRDMCardServer=interface(IAppServer)
       BeginTrans(..);
       CommitTrans(..);
       RollBackTrans(..);
       SelectData(..);
       ExcuteData(..);
     end;软件客户端大体上是这样写的:
fconnection.AppServer.BeginTrans(..);
try
   //一系列的业务操作;
   fconnection.AppServer.SelectData(..);
   fconnection.AppServer.ExcuteData(..);
   ...
   //提交事务
   fconnection.AppServer.CommitTrans(..);except
   //异常则回滚
   fconnection.AppServer.RollBackTrans(..);
end;实现如下:
type
  TRDMCardServer = class(TMtsDataModule, IRDMCardServer)
    fconnection: TADOConnection;
    fProvider: TDataSetProvider;
    fdataset: TADODataSet;
    fcmd: TADOCommand;
    procedure MtsDataModuleActivate(Sender: TObject);
    procedure MtsDataModuleDeactivate(Sender: TObject);
  private
    { Private declarations }
  protected
    class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override;
    procedure BeginTrans(out pResult, pMsg: WideString); safecall;
    procedure CommitTrans(out pResult, pMsg: WideString); safecall;
    procedure SelectData(const sSQL: WideString; out sPrvName: WideString);
      safecall;
    procedure ExecuteData(const sSQL: WideString; out pResult,
      pMsg: WideString); safecall;
    procedure RollBackTrans(var pResult, pMsg: WideString); safecall;
  public
    { Public declarations }
  end;var
  RDMCardServer: TRDMCardServer;implementation{$R *.DFM}class procedure TRDMCardServer.UpdateRegistry(Register: Boolean; const ClassID, ProgID: string);
begin
  if Register then
  begin
    inherited UpdateRegistry(Register, ClassID, ProgID);
    EnableSocketTransport(ClassID);
    EnableWebTransport(ClassID);
  end else
  begin
    DisableSocketTransport(ClassID);
    DisableWebTransport(ClassID);
    inherited UpdateRegistry(Register, ClassID, ProgID);
  end;
end;procedure TRDMCardServer.BeginTrans(out pResult, pMsg: WideString);
begin
  //EnableCommit;
  fconnection.BeginTrans;
end;procedure TRDMCardServer.CommitTrans(out pResult, pMsg: WideString);
begin
  fconnection.CommitTrans;
  //SetComplete;
end;procedure TRDMCardServer.SelectData(const sSQL: WideString;
  out sPrvName: WideString);
var
  par,tmp:OleVariant;
  cnt:integer;
begin
  //EnableCommit;
  fDataSet.Close;
  fDataSet.CommandText:=sSQl;
  fDataSet.Open;
  sPrvName:=fprovider.Name;
end;procedure TRDMCardServer.ExecuteData(const sSQL: WideString; out pResult,
  pMsg: WideString);
var
  par,tmp:OleVariant;
  cnt:integer;
begin
  //EnableCommit;
  try
    fcmd.CommandText:=sSQL;
    fcmd.Execute;
    pResult:='1';
  except
    pResult:='0';
  end;
end;procedure TRDMCardServer.RollBackTrans(var pResult, pMsg: WideString);
begin
 // SetAbort;
  fconnection.RollBackTrans;
end;procedure TRDMCardServer.MtsDataModuleActivate(Sender: TObject);
var
  Path: array[0..MAX_PATH] of Char;
  Result,strPath: String;
begin
  SetString(Result, Path, GetModuleFileName(HInstance, Path, SizeOf(Path)));
  strPath:= ExtractFilePath(Result);
  if not fConnection.Connected then
  begin
    fConnection.ConnectionString := 'FILE NAME=' + strPath + '\Local.UDL' ;
    fConnection.Connected:=True;
  end;
end;procedure TRDMCardServer.MtsDataModuleDeactivate(Sender: TObject);
begin
  fConnection.Connected:=False;
end;initialization
  TComponentFactory.Create(ComServer, TRDMCardServer,
    Class_RDMCardServer, ciMultiInstance, tmBoth);
end.软件中间层只是简单传送了sql语句到数据库服务器,并没有处理业务逻辑,业务逻辑是在客户端通过事务来保证其完整正确性的。
中间层没起到实际作用,但是软件太庞大,不好改太多,我想只要客户端能控制事务也行,可是总是不能回滚。
请高手指点!

解决方案 »

  1.   

    除了改中间层还有其它办法吗?
    我看了com+个把星期了,还是蒙蒙懂懂!
      

  2.   

    看起来是可以Rollback的。不过,因为你自己处理transaction,所以这个元件的TransactionMode要设置为Surport Transaction。
    有几个问题要注意:
    1、跨Database的transaction因为没有DTC支持不行;
    2、使用了状态,从池中取出后再使用时可能状态不对,如池化时还在InTransaction状态。
      

  3.   

    我将上面的函数做如下修改就可以在客户端控制事务了,不过程序因故终止后,在事务中被访问的表还处于某个事务当中,
    当我用SQL Server的企业管理器打开那些表时,表总是处于挂起状态,要等上一段时间,直到Com+组件释放了某些东西(我也不知到是什么东西)才能将表打开!
    这样虽然解决了客户端控制事务的问题,但是如果是多个客户端同时并发执行,而某个正在执行数据库操作的客户端异常终止,导致某些表挂起,就有可能影响其它客户端程序的正常运行,我分析的对吗?如果是这样的这个问题该怎么解决啊?
    procedure   TRDMCardServer.BeginTrans(out   pResult,   pMsg:   WideString); 
    begin 
        //EnableCommit; 
        //fconnection.BeginTrans; 
        fcmd.CommandText:='Begin Tran T1';
        fcmd.Excute;
    end;procedure   TRDMCardServer.CommitTrans(out   pResult,   pMsg:   WideString); 
    begin 
        //fconnection.CommitTrans; 
        //SetComplete;
        fcmd.CommandText:='Commit Tran T1';
        fcmd.Excute; 
    end; procedure   TRDMCardServer.RollBackTrans(var   pResult,   pMsg:   WideString); 
    begin 
      //   SetAbort; 
      //   fconnection.RollBackTrans; 
      fcmd.CommandText:='RollBack Tran T1';
      fcmd.Excute; 
    end;
      

  4.   

    对的,因为BeginTrans与RollBack/Commit是在客户端与服务器的2次通讯中分别完成,但客户端执行了BeginTrans后就死机,就无法调用rollback/commit,只有服务器等待超时后解决transaction。但这不是严重问题,因为对分散式Transaction来说,一样也会有这样的问题存在,不会导致资料异常。严重的是因为Com+的Object Pooling,别的用户可能使用到还在Transaction状态的object。
      

  5.   

    楼上的华华朋友,我对com+接触得很少,目前还处于依葫芦画瓢的水平,对于com+到底是怎么去工作的,看了资料还是模模糊糊,你能讲讲你的体会吗?或者介绍我看看一些易懂的资料!