数据库连接池类

// Writen by 咏南工作室(陈新光) 2009-6-26 11:58:17
// 数据库连接池类
// 使用ADO引擎,支持access, sqlServer, oracle三种数据库
// 连接对象.tag = 正数 表示此连接对象处于非使用状态,否则反之
// 所有时间单位均为秒

unit UDataConnPool;
{$HINTS OFF}
{$WARNINGS OFF}
interface

uses
  SysUtils, Classes, DB, ADODB, Contnrs, Windows, ExtCtrls;

// 常量定义
const
  c_sql = 'sqloledb';
  c_access = 'microsoft.jet.oledb.4.0';
  c_oracle = 'MSDAORA.1';

// 自定义数据类型
type
  TDBType=(Access, SqlServer, Oracle);    // 可支持的数据库类型

  RConnParameter = record                 // 连接池的参数结构体
    ConnMin: Integer;                     // 连接池最小要保留的连接对象数量
    ConnMax: Integer;                     // 连接池最大可拥有的连接对象数量
    TimeOut: Integer;                     // 非使用中连接对象的超时时间
    TimeOut2: Integer;                    // 使用中连接对象的超时时间
    RefreshTime: Integer;                 // 定时轮询连接池的时间
    dbSource: string;                     // data source
    DB: string;                           // sql server 特有 Initial Catalog
    dbUser: string;                       // user id
    dbPass: string;                       // password
    dbpass2: string;                      // access 特有 Database Password
  end;

  TDataConnectionPool = class(TComponent) // 数据库连接池类
  private
    fConnParameter: RConnParameter;                  // 连接池参数
    fConnList: TComponentList;                       // 连接池容器
    fCleanTimer: TTimer;                             // 定时轮询连接池
    fDBType: TDBType;                                // 数据库类型
    procedure fCleanOnTime(sender: TObject);         // 定时轮询连接池
    function fCreateADOConn: TADOConnection;         // 创建连接对象
    procedure fClean;                                // 处理轮询连接池动作
    { Private declarations }
  protected
    function getConnCount: Integer;                  // 获取连接池内的连接对象的总数
  public
    { Public declarations }
    property ConnCount: Integer read getConnCount;   // 连接池内的连接对象的总数
    constructor Create(owner: TComponent; connParam: RConnParameter; dbType: TDBType);  // 创建者方法
    // owner -- 拥有者
    // connParam -- 连接池的参数
    // dbType -- 支持的数据库类型
    function getConn: TADOConnection;                // 从连接池内获取非使用中的连接对象
    procedure returnConn(conn: TADOConnection);      // 使用完的连接对象归还连接池内
end;

implementation

constructor TDataConnectionPool.Create(owner: TComponent; connParam: RConnParameter; dbType: TDBType);
// owner -- 拥有者
// connParam -- 连接池的参数
// dbType -- 支持的数据库类型
var
  index: Integer;
begin
  inherited Create(owner);
  fDBType := dbType;
  fConnParameter := connParam;

  if fConnList = nil then
  begin
    fConnList := TComponentList.Create;            // 创建连接池容器
    for index := 1 to fConnParameter.ConnMin do    // 创建连接对象
      fConnList.Add(fCreateADOConn);
  end;

  if fCleanTimer = nil then                        // 定时轮询连接池
  begin
    fCleanTimer := TTimer.Create(Self);
    fCleanTimer.Name := 'MyCleanTimer1';
    fCleanTimer.Interval := fConnParameter.RefreshTime * 1000;
    fCleanTimer.OnTimer := fCleanOnTime;
    fCleanTimer.Enabled := True;
  end;
end;

procedure TDataConnectionPool.fClean;
var
  iNow: Integer;
  index: Integer;
begin
  iNow := GetTickCount;                                     // 获取当前时间
  for index := fConnList.Count - 1 downto 0 do              // 遍历连接池
  begin
    if TADOConnection(fConnList[index]).Tag > 0 then        // 非使用中的连接
    begin
      if fConnList.Count > fConnParameter.ConnMin then      // 连接池内连接总数 > 最小保留连接数量
      begin
        if iNow - TADOConnection(fConnList[index]).Tag > fConnParameter.TimeOut * 1000 then // 超时
          fConnList.Delete(index);                          // 从连接池内释放此连接对象
      end;
    end
    else if TADOConnection(fConnList[index]).Tag < 0 then   // 使用中的连接
    begin
      if iNow + TADOConnection(fConnList[index]).Tag > fConnParameter.TimeOut2 * 1000 then  // 超时
      begin
        fConnList.Delete(index);                            // 从连接池内释放此连接对象
        if fConnList.Count < fConnParameter.ConnMin then    // 连接池内连接对象 < 最小保留数量
          fConnList.Add(fCreateADOConn);                    // 创建新的连接对象
      end;
    end
  end;
end;

procedure TDataConnectionPool.fCleanOnTime(sender: TObject);
begin
  fClean;
end;

function TDataConnectionPool.fCreateADOConn: TADOConnection;
var
  conn: TADOConnection;
begin
  Conn := TADOConnection.Create(Self);
  with conn do
  begin
    LoginPrompt := False;
    Tag := GetTickCount;

    case fDBType of
      sqlserver:
      begin
        Provider := c_sql;     // 连接SQL SERVER
        Properties['Data Source'].Value := fConnParameter.dbSource;
        Properties['User ID'].Value := fConnParameter.dbUser;
        Properties['Password'].Value := fConnParameter.dbPass;
        Properties['Initial Catalog'].Value := fConnParameter.DB;
      end;

      access:
      begin
        Provider := c_access;   // 连接ACCESS
        Properties['Jet OLEDB:Database Password'].Value := fConnParameter.dbPass2;
        Properties['Data Source'].Value := fConnParameter.dbSource;
        Properties['User ID'].Value := fConnParameter.dbUser;
        Properties['Password'].Value := fConnParameter.dbPass;
      end;

      oracle:                   // 连接ORACLE
      begin
        Provider:=c_oracle;
        Properties['Data Source'].Value := fConnParameter.dbSource;
        Properties['User ID'].Value := fConnParameter.dbUser;
        Properties['Password'].Value := fConnParameter.dbPass;
      end;
    end;

    try                                     // 尝试连接数据库
      Connected := True;
      Result := conn;
    except
      Result := nil;
      raise Exception.Create('Connect database fail.');
    end;
  end;
end;

function TDataConnectionPool.getConn: TADOConnection;// 从连接池内取没有被使用的连接对象
var
  index: Integer;
begin
  Result := nil;
  for index := 0 to fConnList.Count - 1 do           // 遍历连接池
  begin
    if TADOConnection(fConnList[index]).Tag > 0 then // 非使用的连接对象
    begin
      Result := TADOConnection(fConnList[index]);
      Result.Tag := - GetTickCount;                  // 标记该连接为使用状态
      Break;                                         // 找到后中止循环
    end;
  end;

  if (Result = nil) and (index < fConnParameter.ConnMax) then  // 如果连接池内已经没有可用的连接对象(全部被使用)
  begin
    Result := fCreateADOConn;                                  // 在不超过最大连接对象的基础上创建新的连接对象
    Result.Tag := - GetTickCount;                              // 标记为已使用
    fConnList.Add(Result);                                     // 放入连接池内
  end;
end;

function TDataConnectionPool.getConnCount: Integer;
begin
  Result := fConnList.Count;            // 返回当前连接池内总的连接对象数量
end;

procedure TDataConnectionPool.returnConn(conn: TADOConnection);
begin
  if fConnList.IndexOf(conn) > -1 then  // 判断连接池内是否存在此连接对象
    conn.Tag := GetTickCount;           // 标记此连接对象为可用状态
end;

end.

你可能感兴趣的:(数据库连接池)