标签:
所有的数据库都会自动清除掉超时的空闲连接,因为数据库本身是一个SOCKET服务器,它必须要定时清除掉僵死连接,来保持其长时间稳定运行。
数据库清除空闲连接以后,中间件连接池里面con.connected还是等于true,也就是说在中间件里面是无法判断连接池中的连接是否已经被数据库给清除了。
事实上中间件连接池中的所有连接必须保持24小时的连接是通的。那么如何解决这个矛盾呢?
答案是在连接池中设置定时器,定时检查池中的每一个连接,当池中的空闲连接已经超过了半小时,就自动将此连接断开并重连。
{*******************************************************
数据池 陈新光
每一个数据库都有属于自己的数据池,通过帐套编号来标识
更新历史:
ADD BY CXG 2016-8-1 增加定时器
时间戳=0,表示连接被分配,已分配的连接不检查空闲
超过30分钟空闲时间的连接自动断开,并重连
*******************************************************}
unit untDBPool;
interface
uses
Classes, SyncObjs, SysUtils,
DateUtils, untDB, Windows, untGlobal
,Vcl.ExtCtrls
;
type
TDBPool = class
private
FCS: TCriticalSection;
Flist: TList;
FCount: integer;
FDatabaseParams: TDBParams;
FAccountNo: string; // 帐套编号
procedure OnTimer(Sender: TObject);
public
FTimer: TTimer;
constructor Create; overload;
destructor Destroy; override;
procedure Init;
function Lock: TfrmDB;
procedure Unlock(Value: TfrmDB);
function NewObj: TfrmDB;
property Count: integer read FCount default 0;
property DatabaseParams: TDBParams read FDatabaseParams
write FDatabaseParams;
property AccountNo: string read FAccountNo write FAccountNo; // 帐套编号
end;
var
dbPoolList: array of TDBPool; // 数据库池列表
function GetDBPool(const accountNo: string): TDBPool;
implementation
uses untLog;
function GetDBPool(const accountNo: string): TDBPool;
var
i: Integer;
begin
Result := nil;
if accountNo = ‘‘ then
Exit;
for i := Low(dbPoolList) to High(dbPoolList) do
begin
if dbPoolList[i].accountNo = accountNo then
begin
Result := dbPoolList[i];
exit;
end;
end;
end;
constructor TDBPool.Create;
begin
Flist := TList.Create;
FCS := TCriticalSection.Create;
FTimer := TTimer.Create(nil);
FTimer.Enabled := False;
FTimer.Interval := 1000 * 5; // 5 sec
FTimer.OnTimer := Self.OnTimer;
end;
destructor TDBPool.Destroy;
begin
while Flist.Count > 0 do
begin
TfrmDB(Flist[0]).Free;
Flist.Delete(0);
end;
FreeAndNil(Flist);
FreeAndNil(FCS);
FreeAndNil(FTimer);
inherited Destroy;
end;
procedure TDBPool.Init;
var
LDB: TfrmDB;
begin
while Flist.Count < poolParams.poolSize do
begin
LDB := NewObj;
if LDB <> nil then
begin
LDB.ConnectDB;
Flist.Add(LDB);
LDB.TimeStamp := GetTickCount; // 池中连接,开始计算空闲时间
end;
end;
end;
function TDBPool.Lock: TfrmDB;
begin
FCS.Enter;
try
if Flist.Count > 0 then
begin
Result := TfrmDB(Flist[0]);
if not Result.Connected then
Result.ConnectDB;
Flist.Delete(0);
Result.TimeStamp := 0; // =0, 表示连接已被分配占用,不计算空闲时间
end
else
Result := nil;
if Result = nil then
begin
Result := NewObj;
if Result <> nil then
begin
Result.ConnectDB;
Result.Tag := 5;
end;
end;
finally
FCS.Leave;
end;
end;
function TDBPool.NewObj: TfrmDB;
begin
Result := nil;
if poolParams.maxValue = 0 then
begin
Result := TfrmDB.Create(nil);
Result.DatabaseParams := Self.DatabaseParams;
inc(FCount);
end
else if (poolParams.maxValue <> 0) and (FCount < poolParams.maxValue)
then
begin
Result := TfrmDB.Create(nil);
Result.DatabaseParams := Self.DatabaseParams;
inc(FCount);
end;
end;
procedure TDBPool.OnTimer(Sender: TObject);
var
i: Integer;
begin
// 数据库会自动断开长时间空闲的数据连接
FCS.Enter;
try
for I := 0 to Flist.Count - 1 do
begin
if TfrmDB(Flist[i]).TimeStamp = 0 then
Continue // 被分配占用的连接,不计算空闲时间
else
// 池中的连接,空闲时间>30分钟,断开并重连
if ((GetTickCount - TfrmDB(Flist[i]).TimeStamp)) > (1000 * 60 * 30) then
TfrmDB(Flist[i]).ConnectDB;
end;
finally
FCS.Leave;
end;
end;
procedure TDBPool.Unlock(Value: TfrmDB);
procedure _Free;
begin
Value.DisConnectDB;
FreeAndNil(Value);
Dec(FCount);
Value.TimeStamp := GetTickCount; // 归还池中,开始计算连接的空闲时间
end;
begin
if Value = nil then
exit;
FCS.Enter;
try
if Value.Tag = 5 then
begin
_Free;
end
else
begin
if Flist.Count < poolParams.poolSize then
begin
Flist.Add(Value);
end
else
_Free;
end;
finally
FCS.Leave;
end;
end;
end.
数据库会自动清除掉超时的空闲连接造成中间件连接池中连接断开的问题
标签:
原文地址:http://www.cnblogs.com/hnxxcxg/p/5731493.html