ADO数据库连接池类

// 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.
一个使用ADO连接池的示例,演示了TADOStoredProc动态参数的使用,带重连机制 =================== unit UnitDemo; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; //数据库服务器 gDBServer: String = '127.0.0.1'; //数据库名称 gDBName: String = 'master'; //数据库用户名 gDBUser: String = 'sa'; //密码 gDBPass: String = '2001'; implementation {$R *.dfm} uses ADODB, UnitADOConnectionPool; const CreateSQL = 'create procedure TestMyPool (@type sysname) '#13#10+ 'as'#13#10+ 'select * from sysobjects where xtype=@type'#13#10+ 'return @@rowcount'; DeleteSQL = 'if Exists(select 1 from sysobjects where xtype=N''P'' and name=N''TestMyPool'')'#13#10+ ' drop procedure TestMyPool'; var gPoolMan: TADOConnPoolMan = Nil; procedure TForm2.Button1Click(Sender: TObject); var ADOObject:TADOConnPoolObject; ADOStoredProc:TADOStoredProc; Running :Integer; I: Integer; begin //取得一个存储过程资源(含一数据库有效连接) ADOObject := gPoolMan.CreateSP('TestMyPool'); if ADOObject = Nil then //取得资源失败 Exit; try ADOStoredProc := ADOObject.ExecObject as TADOStoredProc; Running := 2;//允许重试(两次)操作,以便在操作失败之后达到重连 while Running>0 do begin Dec(Running); if ADOObject.NeedRefresh then begin//判断是否有重连标志(比如数据库断开等,可能需要进行重连) if Not ADOObject.Reconnect then Exit; ADOObject.NeedRefresh := Not ADOStoredProc.Parameters.Refresh; if ADOObject.NeedRefresh then Exit; end; for I := 1(*Zero is the *Result* Parameter*) to ADOStoredProc.Parameters.Count - 1 do begin //========================= //传递参数 ADOStoredProc.Parameters.Items[I].Value := 'U'; //========================= end; if Running 0 then try //执行存储过程 ADOStoredProc.Open; //执行存储过程成功,退出循环进入后续的数据处理 break; except On E:Exception do begin //执行失败非程序级的异常通常有两种可能: //1.数据库连接断开 //2.自适合的参数传递当中可能存储过程已更新,参与不一致 //设置重连标志 ADOObject.NeedRefresh := True; //=================== //这里记录数据库操作失败日志 //=================== end; end; Exit; end; //========================== //从ADOStoredProc当中读取记录 ShowMessage(IntToStr(ADOStoredProc.Parameters.ParamByName('Result').Value)); //========================== //关闭存储对象的资源 ADOStoredProc.Close; finally //调用结束,释放资源 ADOObject.Free; end; end; procedure TForm2.FormCreate(Sender: TObject); var ADOConn:TADOConnection; begin (****************BEGIN*******************) (*注:仅为测试准备 *) //初始化测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); ADOConn.Execute(CreateSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) //初始化连接池 gPoolMan := TADOConnPoolMan.Create(gDBServer,gDBUser,gDBPass,gDBName,true); end; procedure TForm2.FormDestroy(Sender: TObject); var ADOConn:TADOConnection; begin //释放连接池 if Assigned(gPoolMan) then gPoolMan.Free; (****************BEGIN*******************) (*注:仅为测试准备 *) //清理测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) end; end.
Delphi TThread中文注释2009-10-22 16:58TThread是一个抽象,可以创建几个独立的线程。 关系 TObject 在一个多线程的应用程序中创建一个TThread的后子代表一个线程。每一新子的TThread对象的实例是一个新的线程。从TThread派生的多线程实例可以构成Delphi的多线程应用程序。    当一个应用程序运行时,应用程序就被载入内存准备执行。此时,它成为包含一个或多个线程的进程,每个线程含有数据、代码和系统资源。线程执行应用程序的部分内容,并由系统分配CPU时间。同一进程的所有线程共享同一地址空间,可以访问进程的全局变量。线程通过以下工作改善应用的性能:管理多通信设备的输入。    区分任务的优先级。优先级高的处理紧急的任务。优先级低的处理其他任务。    以下是使用线程的一些建议:    同时跟踪太多的线程消耗CPU时间。对单处理器系统,一个进程最多有16个线程。    当多个线程更新相同的资源时,应使线程同步以避免冲突。    大多数访问VCL对象和更新窗体的方法必须从主VCL线程内部调用。    以下为创建和使用一个新线程的过程:    (1)单击File|New|Thread菜单项,创建一个包含对象的新单元,该对象源于TThread。    (2)定义新线程对象和Create方法。    (3)通过插入线程执行时需要的代码定义线程对象和Execute方法。    (4)将使用VCL组件的任何调用传递给Synchronize方法,以避免多线程冲突。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值