You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi FireDAC连接远程Firebird时误开本地FDB,如何创建远程数据库?

问题

使用Delphi 12.2 Enterprise搭配FireDAC和Firebird 2.5,通过以下代码连接数据库:

type
  TFD3Base = class(TDataModule)
    dbConn: TFDConnection;
  private
    FDBHost: String;
    FDBName: String;
    FPooled: Boolean;
    FLastError: String;
    FConDefName: String;
    {...}
  public
    //connects to the specified database
    procedure Connect(const AHost, AFDB: String);
    //create our tables if they don't exist
    procedure CreateTables;
    {...}
  end;

procedure TFD3Base.Connect(const AHost, AFDB: String);
var
  oDef: IFDStanConnectionDef;
  oParams: TFDPhysFBConnectionDefParams;
begin
  //clear our datamodule's internal vars
  FLastError := '';
  FDBHost := AHost;
  FDBName := AFDB;
  FConDefName := 'BWPMgr_1';

  //if we're already connected, drop it
  if dbConn.Connected then begin
    dbConn.Connected := False;
    try
      FDManager.CloseConnectionDef(FConDefName);
    except
    end;
  end;

  //does our definition exist?
  oDef := FDManager.ConnectionDefs.FindConnectionDef(FConDefName);
  if not Assigned(oDef) then begin
    //no; create it
    oDef := FDManager.ConnectionDefs.AddConnectionDef;
    oDef.Name := FConDefName;

    //build params
    oParams := TFDPhysFBConnectionDefParams(oDef.Params);
    with oParams do begin
      DriverID := 'FB';
      Protocol := ipTCPIP;
      Server   := FDBHost;
      Database := FDBName;
      UserName := 'sysdba';
      Password := 'masterkey';
      OpenMode := omOpenOrCreate;
    end;

    //apply the changes
    oDef.MarkPersistent;
    oDef.Apply;
  end;

  //connect to the FDB if we can
  try
    dbConn.ConnectionDefName := FConDefName;
    dbConn.Params.Pooled := FPooled;
    dbConn.Connected := True;
  except
    on E:Exception do begin
      //save the error msg and re-raise
      FLastError := E.Message;
      raise;
    end;
  end;

  //if we get here, we're connected; create tables as needed
  CreateTables;
  {...}
end;

FDManager已配置为不自动加载,程序启动时会清空所有连接定义。

本地连接时(Server设为localhost,Database设为本地路径),FDB不存在时会自动创建并打开,一切正常。但连接VPN网络中的远程Firebird 2.5服务器时(Server设为远程机器IP,Database设为该机器的本地路径,且与本地路径同名),程序未在远程机器创建FDB,反而打开了本地已存在的FDB。

需要实现:连接远程FDB,若不存在则自动在远程机器创建。

解决方案

问题核心原因:TCP/IP连接远程Firebird时,OpenMode := omOpenOrCreate无法触发服务器端创建数据库——客户端传入的本地路径对远程服务器无意义,FireDAC该参数仅在本地连接时生效,远程场景下会因本地存在同名文件误连本地库。

需通过显式调用Firebird服务API创建远程库,具体步骤如下:

步骤1:添加单元引用

在DataModule的单元中添加FireDAC.Phys.FB和FireDAC.Stan.Intf引用,确保能调用Firebird服务接口。

步骤2:修改Connect方法,增加远程创建逻辑

procedure TFD3Base.Connect(const AHost, AFDB: String);
var
  oDef: IFDStanConnectionDef;
  oParams: TFDPhysFBConnectionDefParams;
  FBService: TFDPhysFBService;
  CreateParams: TFDPhysFBCreateDatabaseParams;
  ConnSuccess: Boolean;
begin
  //clear our datamodule's internal vars
  FLastError := '';
  FDBHost := AHost;
  FDBName := AFDB;
  FConDefName := 'BWPMgr_1';

  //if we're already connected, drop it
  if dbConn.Connected then begin
    dbConn.Connected := False;
    try
      FDManager.CloseConnectionDef(FConDefName);
    except
    end;
  end;

  //does our definition exist?
  oDef := FDManager.ConnectionDefs.FindConnectionDef(FConDefName);
  if not Assigned(oDef) then begin
    //no; create it
    oDef := FDManager.ConnectionDefs.AddConnectionDef;
    oDef.Name := FConDefName;

    //build params
    oParams := TFDPhysFBConnectionDefParams(oDef.Params);
    with oParams do begin
      DriverID := 'FB';
      Protocol := ipTCPIP;
      Server   := FDBHost;
      Database := FDBName;
      UserName := 'sysdba';
      Password := 'masterkey';
      // 远程连接时先尝试正常连接,不使用omOpenOrCreate
      OpenMode := omOpen;
    end;

    //apply the changes
    oDef.MarkPersistent;
    oDef.Apply;
  end;

  // 尝试连接远程数据库
  ConnSuccess := False;
  try
    dbConn.ConnectionDefName := FConDefName;
    dbConn.Params.Pooled := FPooled;
    dbConn.Connected := True;
    ConnSuccess := True;
  except
    on E: Exception do
    begin
      FLastError := E.Message;
      // 判断是否为数据库不存在的错误(匹配Firebird错误码335544344或关键词)
      if (Pos('335544344', E.Message) > 0) or (Pos('isc_err_db_not_found', E.Message) > 0) then
      begin
        // 创建远程数据库
        FBService := TFDPhysFBService.Create(nil);
        try
          FBService.Params.DriverID := 'FB';
          FBService.Params.Protocol := ipTCPIP;
          FBService.Params.Server := FDBHost;
          FBService.Params.UserName := 'sysdba';
          FBService.Params.Password := 'masterkey';
          // 连接到Firebird服务
          FBService.Connected := True;

          // 设置创建数据库的参数
          CreateParams := TFDPhysFBCreateDatabaseParams.Create;
          try
            CreateParams.Database := FDBName;
            // 可根据需求设置页面大小、字符集等参数
            CreateParams.PageSize := 8192;
            CreateParams.Charset := 'UTF8';
            // 执行创建操作
            FBService.CreateDatabase(CreateParams);
          finally
            CreateParams.Free;
          end;

          // 创建成功后再次尝试连接
          dbConn.Connected := True;
          ConnSuccess := True;
        finally
          FBService.Free;
        end;
      end
      else
        raise; // 其他错误直接抛出
    end;
  end;

  //if we get here, we're connected; create tables as needed
  if ConnSuccess then
    CreateTables;
  {...}
end;

额外注意事项

  • 远程路径权限:确保Firebird服务器进程对指定的远程路径有读写权限,否则创建数据库会失败。
  • 端口与防火墙:确保远程机器的Firebird默认端口(3050)在VPN网络中开放,防火墙允许访问。
  • 错误匹配:不同Firebird版本错误提示可能略有差异,建议同时匹配错误码和关键词,避免遗漏。

内容的提问来源于stack exchange,提问作者Steve Sneed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:43:13