// 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.