delphi Firedac中是否存在只读事务的bug?

3phpmpom  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(117)

背景

我的应用程序随机地有只读事务错误,在调试之后,我意识到连接显然保留了上次创建的事务的设置。
这应该是Firedac/PostgreSQL的预期行为,还是它有可能是一个bug?

代码

我能够在一个高度简化的、孤立的代码版本中重现该行为:

program Project1;

    {$APPTYPE CONSOLE}
    {$R *.res}

    uses
      FireDAC.Comp.Client,
      FireDAC.DApt,
      FireDAC.Phys.PG,
      FireDAC.Phys.PGDef,
      FireDAC.Stan.Async,
      FireDAC.Stan.Def,
      FireDAC.Stan.Intf,
      System.SysUtils;
    
    var
      LConnectionDef: IFDStanConnectionDef;
      LQueryRO: TFDQuery;
      LQueryRW: TFDQuery;
      LTransactionRO: TFDTransaction;
      LTransactionRW: TFDTransaction;
      LConnection: TFDCustomConnection;
    begin
      try
        FDManager.DriverDefFileAutoLoad := False;
        FDManager.ConnectionDefs.AutoLoad := False;
        FDManager.ConnectionDefs.Clear;
    
        FDManager.ConnectionDefs.BeginWrite;
        try
          LConnectionDef := FDManager.ConnectionDefs.AddConnectionDef;
          LConnectionDef.Name := 'MY_DB';
    
          with TFDPhysPGConnectionDefParams(LConnectionDef.Params) do
          begin
            DriverID := 'PG';
            CharacterSet := TFDPGCharacterSet.csUTF8;
            Server := '127.0.0.1';
            Database := 'public';
            Port  := 11786;
            UserName := 'my_user';
            Password := '123456';
          end;
        finally
          FDManager.ConnectionDefs.EndWrite;
        end;
    
        LConnection := FDManager.AcquireConnection('MY_DB', '');
    
        LTransactionRO := TFDTransaction.Create(nil);
        LQueryRO := TFDQuery.Create(nil);
        try
          LTransactionRO.Connection := LConnection;
          LTransactionRO.Options.ReadOnly := True;
    
          LQueryRO.Connection := LConnection;
          LQueryRO.Transaction := LTransactionRO;
    
          LQueryRO.Open('SELECT * FROM MY_TABLE');
        finally
          LQueryRO.Free;
          LTransactionRO.Free;
        end;
    
        LTransactionRW := TFDTransaction.Create(nil);
        LQueryRW := TFDQuery.Create(nil);
        try
          LTransactionRW.Connection := LConnection;
          LTransactionRW.Options.ReadOnly := False;
    
          LQueryRW.Connection := LConnection;
          LQueryRW.Transaction := LTransactionRW;
    
          //ERROR: cannot execute UPDATE in a read-only transaction.
          LQueryRW.ExecSQL('UPDATE MY_TABLE SET COLUMN_1 = COLUMN_1 WHERE 1=1');
        finally
          LQueryRW.Free;
          LTransactionRW.Free;
        end;
    
        Writeln('OK');
        Readln;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.

**注1:**如果我注解了LTransactionRO.Options.ReadOnly := True;行,UPDATE SQL运行时没有错误。
**注2:**我正在 Delphi Alexandria 进行测试

cclgggtu

cclgggtu1#

如文档FireDAC.Stan.Option.TFDTxOptions.ReadOnly中所述
使用ReadOnly属性值通知DBMS事务只读取数据,但不修改数据。默认值为False。将ReadOnly属性设置为True允许DBMS优化资源使用。
不修改当前事务。最好明确指定StartTransaction、Commit、Rollback。
释放TFDQuery不会自动关闭事务。

相关问题