使用FireDAC的TFDManager和TFDConnection组件实现运行时动态数据库连接

以下是一个通用的数据库连接方案,使用FireDAC的TFDManagerTFDConnection组件实现运行时动态数据库连接。支持多种数据库类型,采用面向对象封装:

 

unit DatabaseManager;


interface


uses
  System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
  FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Comp.Client,
  FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB,
  FireDAC.Comp.DataSet;


type
  TDatabaseType = (dtSQLite, dtMySQL, dtPostgreSQL, dtMSSQL, dtOracle);


  TDatabaseManager = class
  private
    FConnection: TFDConnection;
    FManager: TFDManager;
    FDatabaseType: TDatabaseType;
    FLastError: string;
    procedure ValidateDriver;
    function GetConnectionDefName: string;
    function GetDriverName: string;
    function BuildParams(Params: TStrings): string;
  public
    constructor Create;
    destructor Destroy; override;
    procedure ConfigureConnection(DatabaseType: TDatabaseType; Params: TStrings);
    function Connect: Boolean;
    procedure Disconnect;
    function ExecSQL(const SQL: string; Params: TArray<TVarRec>): Integer;
    function OpenQuery(const SQL: string; Params: TArray<TVarRec>): TFDQuery;
    property LastError: string read FLastError;
  end;


implementation


{ TDatabaseManager }


constructor TDatabaseManager.Create;
begin
  FManager := TFDManager.Create(nil);
  FConnection := TFDConnection.Create(nil);
  FManager.SilentMode := True;
  FManager.Active := True;
end;


destructor TDatabaseManager.Destroy;
begin
  Disconnect;
  FConnection.Free;
  FManager.Free;
  inherited;
end;


procedure TDatabaseManager.ConfigureConnection(DatabaseType: TDatabaseType; Params: TStrings);
begin
  FDatabaseType := DatabaseType;
  FManager.ConnectionDefs.Clear;


  // 添加新的连接定义
  FManager.AddConnectionDef(
    GetConnectionDefName,
    GetDriverName,
    BuildParams(Params)
  );
end;


function TDatabaseManager.Connect: Boolean;
begin
  Result := False;
  try
    ValidateDriver;
    FConnection.ConnectionDefName := GetConnectionDefName;
    FConnection.Connected := True;
    Result := True;
    FLastError := '';
  except
    on E: Exception do
      FLastError := '连接失败: ' + E.Message;
  end;
end;


procedure TDatabaseManager.Disconnect;
begin
  if FConnection.Connected then
    FConnection.Connected := False;
end;


function TDatabaseManager.ExecSQL(const SQL: string; Params: TArray<TVarRec>): Integer;
var
  Query: TFDQuery;
begin
  Result := -1;
  Query := TFDQuery.Create(nil);
  try
    Query.Connection := FConnection;
    Query.SQL.Text := SQL;
    if Length(Params) > 0 then
      Query.MacroByName('params').Value := Params;
    Query.ExecSQL;
    Result := Query.RowsAffected;
  finally
    Query.Free;
  end;
end;


function TDatabaseManager.OpenQuery(const SQL: string; Params: TArray<TVarRec>): TFDQuery;
begin
  Result := TFDQuery.Create(nil);
  try
    Result.Connection := FConnection;
    Result.SQL.Text := SQL;
    if Length(Params) > 0 then
      Result.MacroByName('params').Value := Params;
    Result.Open;
  except
    Result.Free;
    raise;
  end;
end;


// 私有方法实现
procedure TDatabaseManager.ValidateDriver;
begin
  case FDatabaseType of
    dtSQLite: FDPhysSQLiteDriverLink.Create(nil);
    dtMySQL: FDPhysMySQLDriverLink.Create(nil);
    dtPostgreSQL: FDPhysPgDriverLink.Create(nil);
    dtMSSQL: FDPhysMSSQLDriverLink.Create(nil);
    dtOracle: FDPhysOracleDriverLink.Create(nil);
  end;
end;


function TDatabaseManager.GetConnectionDefName: string;
begin
  Result := Format('%s_Connection', [GetEnumName(TypeInfo(TDatabaseType), Ord(FDatabaseType))]);
end;


function TDatabaseManager.GetDriverName: string;
begin
  case FDatabaseType of
    dtSQLite: Result := 'SQLite';
    dtMySQL: Result := 'MySQL';
    dtPostgreSQL: Result := 'PG';
    dtMSSQL: Result := 'MSSQL';
    dtOracle: Result := 'Ora';
  else
    raise Exception.Create('不支持的数据库类型');
  end;
end;


function TDatabaseManager.BuildParams(Params: TStrings): string;
var
  I: Integer;
begin
  Result := '';
  for I := 0 to Params.Count - 1 do
    Result := Result + Format('%s=%s;', [Params.Names[I], Params.ValueFromIndex[I]]);
end;


end.

 

使用示例:

 

// 创建数据库管理器
var
  DB: TDatabaseManager;
  Params: TStringList;
  Query: TFDQuery;
begin
  DB := TDatabaseManager.Create;
  try
    // 配置SQLite连接
    Params := TStringList.Create;
    try
      Params.Values['Database'] := 'C:\Data\mydb.sqlite';
      Params.Values['OpenMode'] := 'CreateUTF8';
      DB.ConfigureConnection(dtSQLite, Params);
    finally
      Params.Free;
    end;


    if DB.Connect then
    begin
      // 执行SQL命令
      DB.ExecSQL('CREATE TABLE IF NOT EXISTS Users (ID INTEGER PRIMARY KEY, Name TEXT)');


      // 执行查询
      Query := DB.OpenQuery('SELECT * FROM Users');
      try
        while not Query.Eof do
        begin
          ShowMessage(Query.FieldByName('Name').AsString);
          Query.Next;
        end;
      finally
        Query.Free;
      end;
    end
    else
      ShowMessage(DB.LastError);
  finally
    DB.Free;
  end;
end;

 

功能特点:

 

  1. 多数据库支持
    • 支持SQLite、MySQL、PostgreSQL、SQL Server和Oracle
    • 通过TDatabaseType枚举轻松扩展新数据库类型
  2. 动态配置
  3.  
  4. 安全连接管理
    • 自动验证数据库驱动
    • 内置错误处理机制
    • 连接资源自动释放
  5. 灵活的参数化查询
  6.  
  7. 事务支持(可扩展):
  8.  

 

配置参数说明:

 

数据库类型

必需参数

示例值

SQLite

Database, OpenMode

Database=C:\data\test.sdb

MySQL

Server, Database, User_Name, Password

Server=192.168.1.100;Port=3306

PostgreSQL

Server, Database, User_Name, Password

Port=5432

MSSQL

Server, Database, User_Name, Password

OSAuthent=Yes

Oracle

Server, User_Name, Password

ServiceName=ORCL

 

最佳实践建议:

 

  1. 连接池配置
  2.  
  3. 性能优化
  4.  
  5. 安全增强
  6.  
  7. 日志记录
  8.  
  9. 多线程支持
  10.  

 

该方案通过面向对象设计实现了以下优势:

1. 高内聚低耦合:数据库操作逻辑与业务逻辑分离

2. 可扩展性:新增数据库类型只需扩展枚举和驱动验证

3. 类型安全:强类型参数减少运行时错误

4. 资源管理:自动释放连接和查询对象

5. 统一接口:所有数据库操作使用相同的方法签名

 

可根据具体需求扩展以下功能:

 

  • 连接状态监控
  • 执行计划分析
  • 批量数据操作
  • 数据库元数据查询
  • 异步操作支持
  • 连接故障转移机制
posted @ 2025-11-05 17:04  麦麦提敏  阅读(9)  评论(0)    收藏  举报