几种写法,暂时还没有细看。先转了再说:
1、
unit AdoconnectPool;
interface
uses
Classes, Windows, SysUtils, ADODB, IniFiles, forms;
type
TADOConnectionPool = class(TObject)
private
FObjList:TThreadList;
FTimeout: Integer;
FMaxCount: Integer;
FSemaphore: Cardinal;
function CreateNewInstance(List:TList): TADOConnection;
function GetLock(List:TList;Index: Integer): Boolean;
public
property Timeout:Integer read FTimeout write FTimeout;
property MaxCount:Integer read FMaxCount;
constructor Create(ACapicity:Integer=30);overload;
destructor Destroy;override;
function Lock: TADOConnection;
procedure Unlock(var Value: TADOConnection);
end;
var
ConnPool: TADOConnectionPool;
g_ini: TIniFile;
implementation
constructor TADOConnectionPool.Create(ACapicity:Integer=30);
begin
FObjList:=TThreadList.Create;
FTimeout := 3000; // 3 second
FMaxCount := ACapicity;
FSemaphore := CreateSemaphore(nil, FMaxCount, FMaxCount, nil);
end;
function TADOConnectionPool.CreateNewInstance(List:TList): TADOConnection;
var
p: TADOConnection;
function GetConnStr: string;
begin
try
Result := g_ini.ReadString('ado','connstr','');
except
Exit;
end;
end;
begin
try
p := TADOConnection.Create(nil);
p.ConnectionString := GetConnStr;
p.LoginPrompt := False;
p.Connected:=True;
p.Tag := 1;
List.Add(p);
Result := p;
except
on E: Exception do
begin
Result := nil;
Exit;
end;
end;
end;
destructor TADOConnectionPool.Destroy;
var
i: Integer;
List:TList;
begin
List:=FObjList.LockList;
try
for i := List.Count - 1 downto 0 do
begin
TADOConnection(List[i]).Free;
end;
finally
FObjList.UnlockList;
end;
FObjList.Free;
FObjList := nil;
CloseHandle(FSemaphore);
inherited;
end;
function TADOConnectionPool.GetLock(List:TList;Index: Integer): Boolean;
begin
try
Result := TADOConnection(List[Index]).Tag = 0;
if Result then
TADOConnection(List[Index]).Tag := 1;
except
Result :=False;
Exit;
end;
end;
function TADOConnectionPool.Lock: TADOConnection;
var
i: Integer;
List:TList;
begin
try
Result :=nil;
if WaitForSingleObject(FSemaphore, Timeout) = WAIT_FAILED then Exit;
List:=FObjList.LockList;
try
for i := 0 to List.Count - 1 do
begin
if GetLock(List,i) then
begin
Result := TADOConnection(List[i]);
PostMessage(Application.MainForm.Handle,8888,13,0);
Exit;
end;
end;
if List.Count < MaxCount then
begin
Result := CreateNewInstance(List);
PostMessage(Application.MainForm.Handle,8888,11,0);
end;
finally
FObjList.UnlockList;
end;
except
Result := nil;
Exit;
end;
end;
procedure TADOConnectionPool.Unlock(var Value: TADOConnection);
var
List:TList;
begin
try
List:=FObjList.LockList;
try
TADOConnection(List[List.IndexOf(Value)]).Tag :=0;
ReleaseSemaphore(FSemaphore, 1, nil);
finally
FObjList.UnlockList;
end;
PostMessage(Application.MainForm.Handle, 8888, 12, 0);
except
Exit;
end;
end;
initialization
ConnPool := TADOConnectionPool.Create();
g_ini := TIniFile.Create(ExtractFilePath(Application.ExeName)+'server.ini');
finalization
FreeAndNil(ConnPool);
FreeAndNil(g_ini);
end.
2.
Delphi做服务器端如果每次请求都创建一个连接就太耗资源了,而使用一个全局的连接那效率可想而知,这样就体现出了线程池的重要了。参考一些例子做了个ADO的连接池,用到项目中挺不错的,分享下。
{ ******************************************************* }
{ Description : ADO连接池 }
{ Create Date : 2010-8-31 23:22:09 }
{ Modify Remark :2010-9-1 12:00:09 }
{ Modify Date : }
{ Version : 1.0 }
{ ******************************************************* }
unit ADOConnectionPool;
interface
uses
Classes, Windows, SyncObjs, SysUtils, ADODB;
type
TADOConnectionPool = class(TObject)
private
FConnectionList:TThreadList;
//FConnList: TList;
FTimeout: Integer;
FMaxCount: Integer;
FSemaphore: Cardinal;
//FCriticalSection: TCriticalSection;
FConnectionString,
FDataBasePass,
FDataBaseUser:string;
function CreateNewInstance(AOwnerList:TList): TADOConnection;
function GetLock(AOwnerList:TList;Index: Integer): Boolean;
public
property ConnectionString:string read FConnectionString write FConnectionString;
property DataBasePass:string read FDataBasePass write FDataBasePass;
property DataBaseUser:string read FDataBaseUser write FDataBaseUser;
property Timeout:Integer read FTimeout write FTimeout;
property MaxCount:Integer read FMaxCount;
constructor Create(ACapicity:Integer=15);overload;
destructor Destroy;override;
/// <summary>
/// 申请并一个连接并上锁,使用完必须调用UnlockConnection来释放锁
/// </summary>
function LockConnection: TADOConnection;
/// <summary>
/// 释放一个连接
/// </summary>
procedure UnlockConnection(var Value: TADOConnection);
end;
type
PRemoteConnection=^TRemoteConnection;
TRemoteConnection=record
Connection : TADOConnection;
InUse:Boolean;
end;
var
ConnectionPool: TADOConnectionPool;
implementation
constructor TADOConnectionPool.Create(ACapicity:Integer=15);
begin
//FConnList := TList.Create;
FConnectionList:=TThreadList.Create;
//FCriticalSection := TCriticalSection.Create;
FTimeout := 15000;
FMaxCount := ACapicity;
FSemaphore := CreateSemaphore(nil, FMaxCount, FMaxCount, nil);
end;
function TADOConnectionPool.CreateNewInstance(AOwnerList:TList): TADOConnection;
var
p: PRemoteConnection;
begin
Result := nil;
New(p);
p.Connection := TADOConnection.Create(nil);
p.Connection.ConnectionString := ConnectionString;
p.Connection.LoginPrompt := False;
try
if (DataBaseUser='') and (DataBasePass='') then
p.Connection.Connected:=True
else
p.Connection.Open(DataBaseUser, DataBasePass);
except
p.Connection.Free;
Dispose(p);
raise;
Exit;
end;
p.InUse := True;
AOwnerList.Add(p);
Result := p.Connection;
end;
destructor TADOConnectionPool.Destroy;
var
i: Integer;
ConnList:TList;
begin
//FCriticalSection.Free;
ConnList:=FConnectionList.LockList;
try
for i := ConnList.Count - 1 downto 0 do
begin
try
PRemoteConnection(ConnList[i]).Connection.Free;
Dispose(ConnList[i]);
except
//忽略释放错误
end;
end;
finally
FConnectionList.UnlockList;
end;
FConnectionList.Free;
CloseHandle(FSemaphore);
inherited Destroy;
end;
function TADOConnectionPool.GetLock(AOwnerList:TList;Index: Integer): Boolean;
begin
Result := not PRemoteConnection(AOwnerList[Index]).InUse;
if Result then
PRemoteConnection(AOwnerList[Index]).InUse := True;
end;
function TADOConnectionPool.LockConnection: TADOConnection;
var
i,WaitResult: Integer;
ConnList:TList;
begin
Result := nil;
WaitResult:= WaitForSingleObject(FSemaphore, Timeout);
if WaitResult = WAIT_FAILED then
raise Exception.Create('Server busy, please try again');
ConnList:=FConnectionList.LockList;
try
try
for i := 0 to ConnList.Count - 1 do
begin
if GetLock(ConnList,i) then
begin
Result := PRemoteConnection(ConnList[i]).Connection;
Exit;
end;
end;
if ConnList.Count < MaxCount then
Result := CreateNewInstance(ConnList);
except
// 获取信号且失败则释放一个信号量
if WaitResult=WAIT_OBJECT_0 then
ReleaseSemaphore(FSemaphore, 1, nil);
raise;
end;
finally
FConnectionList.UnlockList;
end;
if Result = nil then
begin
if WaitResult=WAIT_TIMEOUT then
raise Exception.Create('Timeout expired.Connection pool is full.')
else
{ This shouldn 't happen because of the sempahore locks }
raise Exception.Create('Unable to lock Connection');
end;
end;
procedure TADOConnectionPool.UnlockConnection(var Value: TADOConnection);
var
i: Integer;
ConnList:TList;
begin
ConnList:=FConnectionList.LockList;
try
for i := 0 to ConnList.Count - 1 do
begin
if Value = PRemoteConnection(ConnList[i]).Connection then
begin
PRemoteConnection(ConnList[I]).InUse := False;
ReleaseSemaphore(FSemaphore, 1, nil);
break;
end;
end;
finally
FConnectionList.UnlockList;
end;
end;
initialization
ConnectionPool := TADOConnectionPool.Create();
finalization
ConnectionPool.Free;
end.
3.
当连接数多,使用频繁时,用连接池大大提高效率
unit uDBPool;
interface
uses Classes ,ADODB,ADOInt,Messages,SysUtils,DataDefine,Windows , Forms,
Dialogs;
type
TDBPool = class
private
FList :TList;
FbLoad :Boolean;
FsConnStr :String;
FbResetConnect: Boolean; //是否准备复位所有的连接
CS_GetConn: TRTLCriticalSection;
FConnStatus: Boolean;// ADOConnection 连接状态
procedure Clear;
procedure Load;
protected
procedure ConRollbackTransComplete(
Connection: TADOConnection; const Error: ADOInt.Error;
var EventStatus: TEventStatus);
procedure ConCommitTransComplete(
Connection: TADOConnection; const Error: ADOInt.Error;
var EventStatus: TEventStatus);
procedure ConBeginTransComplete(
Connection: TADOConnection; TransactionLevel: Integer;
const Error: ADOInt.Error; var EventStatus: TEventStatus);
public
constructor Create(ConnStr :string);
destructor Destroy; override;
procedure Reset;
function GetConnection: PRecConnection;
procedure AddConnetion ; // GetConnection繁忙遍历多次时,添加新连接
procedure FreeIdleConnetion ; // 销毁闲着的链接
procedure RemoveConnection(ARecConnetion: PRecConnection);
procedure CloseConnection; //关闭所有连接
property bConnStauts : Boolean read FConnStatus write FConnStatus default True;
end;
var
DataBasePool : TDBPool;
implementation
{ TDBPool }
procedure TDBPool.ConRollbackTransComplete(
Connection: TADOConnection; const Error: ADOInt.Error;
var EventStatus: TEventStatus);
begin
Now_SWcount := Now_SWcount-1;
end;
procedure TDBPool.ConCommitTransComplete(
Connection: TADOConnection; const Error: ADOInt.Error;
var EventStatus: TEventStatus);
begin
Now_SWcount := Now_SWcount-1;
end;
procedure TDBPool.ConBeginTransComplete(
Connection: TADOConnection; TransactionLevel: Integer;
const Error: ADOInt.Error; var EventStatus: TEventStatus);
begin
Now_SWcount := Now_SWcount+1;
end;
constructor TDBPool.Create(ConnStr: string);
begin
inherited Create;
InitializeCriticalSection(CS_GetConn); //初始临界区对象。
FbResetConnect := False;
FList := TList.Create;
FbLoad := False;
FsConnStr := ConnStr;
Load;
end;
destructor TDBPool.Destroy;
begin
Clear;
FList.Free;
DeleteCriticalSection(CS_GetConn);
inherited;
end;
procedure TDBPool.Clear;
var
i:Integer;
tmpRecConn :PRecConnection;
begin
for i:= 0 to FList.Count-1 do
begin
tmpRecConn := FList.items[i];
tmpRecConn^.ADOConnection.Close;
tmpRecConn^.ADOConnection.Free;
Dispose(tmpRecConn);
FList.Items[i] := nil;
end;
FList.Pack;
FList.Clear;
end;
procedure TDBPool.Load;
var
i :Integer;
tmpRecConn :PRecConnection;
AdoConn :TADOConnection;
begin
if FbLoad then Exit;
Clear;
for i:=1 to iConnCount do
begin
AdoConn := TADOConnection.Create(nil);
AdoConn.ConnectionString:= FsConnStr;
AdoConn.OnRollbackTransComplete := ConRollbackTransComplete;
AdoConn.OnCommitTransComplete := ConCommitTransComplete;
AdoConn.OnBeginTransComplete := ConBeginTransComplete;
// AdoConn.Open;
AdoConn.LoginPrompt := False;
New(tmpRecConn);
tmpRecConn^.ADOConnection := AdoConn;
tmpRecConn^.isBusy := False;
FList.Add(tmpRecConn);
FConnStatus := True;
end;
end;
procedure TDBPool.Reset;
begin
FbLoad := False;
Load;
end;
function TDBPool.GetConnection: PRecConnection;
var
i :Integer;
tmpRecConnection :PRecConnection;
bFind :Boolean ;
begin
Result := nil;
// 1、加互斥对象,防止多客户端同时访问
// 2、改为循环获取连接,知道获取到为止
// 3、加判断ADOConnection 没链接是才打开
EnterCriticalSection(CS_GetConn);
bFind :=False ;
try
try
//iFindFount :=0 ;
while (not bFind) and (not FbResetConnect) do
begin
// if not FConnStatus then //当测试断线的时候可能ADOConnection的状态不一定为False
// Reset;
for i:= 0 to FList.Count-1 do
begin
//PRecConnection(FList.Items[i])^.ADOConnection.Close ;
tmpRecConnection := FList.Items[i];
if not tmpRecConnection^.isBusy then
begin
if not tmpRecConnection^.ADOConnection.Connected then
tmpRecConnection^.ADOConnection.Open;
tmpRecConnection^.isBusy := True;
Result := tmpRecConnection;
bFind :=True ;
Break;
end;
end;
application.ProcessMessages;
Sleep(50) ;
{ Inc(iFindFount) ;
if(iFindFount>=1) then
begin // 遍历5次还找不到空闲连接,则添加链接
AddConnetion ;
end; }
end ;
except
on e: Exception do
raise Exception.Create('TDBPOOL.GetConnection-->' + e.Message);
end;
finally
LeaveCriticalSection(CS_GetConn);
end ;
end;
procedure TDBPool.RemoveConnection(ARecConnetion: PRecConnection);
begin
if ARecConnetion^.ADOConnection.InTransaction then
ARecConnetion^.ADOConnection.CommitTrans;
ARecConnetion^.isBusy := False;
end;
procedure TDBPool.AddConnetion;
var
i,uAddCount :Integer ;
tmpRecConn :PRecConnection;
AdoConn : TADOConnection ;
begin
if FList.Count >= iMaxConnCount then
Exit ;
if iMaxConnCount - FList.Count > 10 then
begin
uAddCount :=10 ;
end else
begin
uAddCount :=iMaxConnCount - FList.Count ;
end;
for i:=1 to uAddCount do
begin
AdoConn := TADOConnection.Create(nil);
AdoConn.ConnectionString:= FsConnStr;
AdoConn.OnRollbackTransComplete := ConRollbackTransComplete;
AdoConn.OnCommitTransComplete := ConCommitTransComplete;
AdoConn.OnBeginTransComplete := ConBeginTransComplete;
// AdoConn.Open;
AdoConn.LoginPrompt := False;
New(tmpRecConn);
tmpRecConn^.ADOConnection := AdoConn;
tmpRecConn^.isBusy := False;
FList.Add(tmpRecConn);
Dispose(tmpRecConn) ;
end;
end;
procedure TDBPool.FreeIdleConnetion;
var
i,uFreeCount,uMaxFreeCount :Integer ;
tmpRecConn : PRecConnection ;
begin
if FList.Count<=iConnCount then
Exit ;
uMaxFreeCount :=FList.Count- iConnCount ;
uFreeCount :=0 ;
for i:= 0 to FList.Count do
begin
if (uFreeCount>=uMaxFreeCount) then
Break ;
// New(tmpRecConn) ;
tmpRecConn := FList.items[i];
if tmpRecConn^.isBusy =False then
begin
tmpRecConn^.ADOConnection.Close;
tmpRecConn^.ADOConnection.Free;
uFreeCount :=uFreeCount +1 ;
end;
Dispose(tmpRecConn);
FList.Items[i] := nil;
end;
FList.Pack;
end;
procedure TDBPool.CloseConnection;
begin
FbResetConnect := True;
EnterCriticalSection(CS_GetConn);
try
Reset;
finally
LeaveCriticalSection(CS_GetConn);
FbResetConnect := False;
end;
end;
end.