DELPHI的FireDac连接池单元
<p> </p><p><br>(*******************************************************************************<br> FireDac连接池<br>*******************************************************************************<br>池满的情况下 池子DAC连接 动态创建<br>系统默认池子中 一个小时以上未用的 TFDConnection 连接 系统自动释放<br>使用如下<br>先Uses SQLFirDACPoolUnit 单元<br>在程序初始化时(initialization)创建连接池类<br>DAConfig := TDAConfig.Create('YxDServer.ini');<br>DACPool := TDACPool.Create(32);<br>在程序关闭时(finalization)释放连接池类<br>DACPool.Free;<br>DAConfig.Free;<br>调用如下<br>try<br>FDQuery.Connecttion:= DACPool.GetCon(DAConfig);<br>FDQuery.Open;<br>finally<br>DACPool.PutCon(FDQuery.Connecttion);<br>end;<br>QQ:2405414352<br>2021-3<br>如有优化 请传一份 。谢谢!<br>*********************************************************************************<br>代码源自:作者:何应祖--SQLADOPoolUnit.pas<br>********************************************************************************)</p>
<p>unit SQLFirDACPoolUnit;</p>
<p>interface</p>
<p>uses<br>Windows, SqlExpr, SysUtils, Classes, ExtCtrls, DateUtils, IniFiles, uEncry,<br>Messages, Provider, FireDAC.Comp.Client, FireDAC.Phys.MSSQL,<br>FireDAC.DApt,FireDAC.Moni.FlatFile,FireDAC.Stan.Intf,<br>FireDAC.Moni.Base,QLog;</p>
<p>type// 数据库类型<br>TDBType = (Access, SqlServer, Oracle);<br>//数据库配置 DAC</p>
<p>type<br>TDAConfig = class<br>private<br>//数据库配置<br> ConnectionName: string; //连接驱动名字<br> ProviderName: string; //通用驱动<br> DBServer: ansistring; //数据源 --数据库服务器IP<br> DataBase: ansistring; //数据库名字 //sql server连接时需要数据库名参数--数据库实例名称<br> OSAuthentication: Boolean; //是否是windows验证<br> UserName: ansistring; //数据库用户<br> PassWord: ansistring; //密码<br> AccessPassWord: string; //Access可能需要数据库密码<br> Port: integer; //数据库端口<br> DriverName: string; //驱动<br> HostName: string; //服务地址<br>//端口配置<br> TCPPort: Integer; //TCP端口<br> HttpPort: Integer; //http 端口<br> LoginSrvUser: string; //验证中间层服务登录用户<br> LoginSrvPassword: string; //验证登录模块密码<br>public<br> constructor Create(iniFile: string); overload;<br> destructor Destroy; override;<br>end;</p>
<p>type<br>TDACon = class<br>private<br> FConnObj: TFDConnection; //数据库连接对象<br> FAStart: TDateTime; //最后一次活动时间<br> function GetUseFlag: Boolean;<br> procedure SetUseFlag(value: Boolean);<br> procedure FDMFFOutput(ASender: TFDMoniClientLinkBase; const AClassName,<br> AObjName, AMessage: string);<br>public<br> constructor Create(DAConfig: TDAConfig); overload;<br> destructor Destroy; override;<br>//当前对象是否被使用<br> property UseFlag: boolean read GetUseFlag write SetUseFlag;<br> property ConnObj: TFDConnection read FConnObj;<br> property AStart: TDateTime read FAStart write FAStart;<br>end;</p>
<p>type<br>TDACPool = class<br> procedure OnMyTimer(Sender: TObject); //做轮询用<br>private<br> //FSection: TRTLCriticalSection;<br> FPoolNumber: Integer; //池大小<br> FPollingInterval: Integer; //轮询时间 以 分 为单位<br> FDACon: TDACon;<br> FList: TList; //用来管理连接<br> FTime: TTimer; //主要做轮询<br> procedure Enter;<br> procedure Leave;<br> function SameConfig(const Source: TDAConfig; Target: TDACon): Boolean;<br> function GetConnectionCount: Integer;<br>public<br> constructor Create(const MaxNumBer: Integer; FreeMinutes: Integer = 60;<br> TimerTime: Integer = 5000); overload;<br> destructor Destroy; override;<br>//从池中取出可用的连接。<br> function GetCon(const tmpConfig: TDAConfig): TFDConnection;<br>//把用完的连接放回连接池。<br> procedure PutCon(const DAConnection: TFDConnection);<br>//释放池中许久未用的连接,由定时器定期扫描执行<br> procedure FreeConnection;<br>//当前池中连接数.<br> property ConnectionCount: Integer read GetConnectionCount;<br>end;</p>
<p>var<br>DACPool: TDACPool;<br>DAConfig: TDAConfig;<br>PoolNum: Integer = 32;</p>
<p>implementation<br>{ TDAConfig }</p>
<p>constructor TDAConfig.Create(iniFile: string);<br>var<br>AINI: TIniFile;<br>begin<br>try<br> AINI := TIniFile.Create(iniFile);<br> DBServer := AINI.ReadString('DB', 'Server', '');<br> DataBase := AINI.ReadString('DB', 'DataBase', '');<br> DBServer := DeCode(AINI.ReadString('DB', 'Server', ''));<br> DataBase := DeCode(AINI.ReadString('DB', 'DataBase', ''));<br> UserName := DeCode(AINI.ReadString('DB', 'UserName', ''));<br> PassWord := DeCode(AINI.ReadString('DB', 'PassWord', ''));<br> PoolNum := AINI.ReadInteger('YxCisSvr', 'Pools', 32);<br>finally<br> Freeandnil(AINI);<br>end;</p>
<p>end;</p>
<p>destructor TDAConfig.Destroy;<br>begin<br>inherited;<br>end;<br>{ tdacon }</p>
<p>procedure TDACon.FDMFFOutput(ASender: TFDMoniClientLinkBase;<br>const AClassName, AObjName, AMessage: string);<br>begin<br>PostLog(llDebug,AMessage);<br>end;</p>
<p>constructor TDACon.Create(DAConfig: TDAConfig);<br>var<br>str: string;<br>begin<br>str := 'DriverID=MSSQL;Server=' + DAConfig.DBServer + ';Database=' + DAConfig.DataBase<br> + ';User_name=' + DAConfig.UserName + ';Password=' + DAConfig.PassWord;<br>FConnObj := TFDConnection.Create(nil);<br>with FConnObj do<br>begin<br> //ConnectionTimeout:=18000;<br> ConnectionString := str;<br> //解决执行sql过程断线,等待时间过程 ,加上之后,数据量过大写入会超时!屏蔽!<br> //Params.add('ResourceOptions.CmdExecTimeout=3');<br> //解决查询只返回50条数据问题<br> Params.add('FetchOptions.Mode=fmAll');<br> //解决!,&等字符插入数据库时丢失<br> Params.add('ResourceOptions.MacroCreate=False');<br> Params.add('ResourceOptions.MacroExpand=False');<br> //////////SQL日志设置/////////<br> //Params.add('MonitorBy=FlatFile');<br> //Params.add('ConnectionIntf.Tracing=True');<br> //FileName := '';<br> //EventKinds := ;<br> //ShowTraces := False;<br> //OnOutput := FDMFFOutput;<br> //try<br> //FileEncoding := ecANSI;<br> //Except<br> //raise Exception.Create('正在初始化SQL跟踪日志!请重新提交数据!');<br> //end;<br> ///////////////////////////<br> try<br> Connected := True;<br> //Tracing := DAConfig.BDEBUG;<br> except<br> raise Exception.Create('数据库连接失败!请检查数据库配置或者网络链接!');<br> end;<br>end;<br>end;</p>
<p>destructor tdacon.Destroy;<br>begin<br>FAStart := 0;<br>if Assigned(FConnObj) then<br>begin<br> if FConnObj.Connected then<br> FConnObj.Close;<br> FreeAndnil(FConnObj);<br>end;<br>inherited;<br>end;</p>
<p>procedure tdacon.SetUseFlag(value: Boolean);<br>begin<br>//False表示闲置,True表示在使用。<br>if not value then<br> FConnObj.Tag := 0<br>else<br>begin<br> if FConnObj.Tag = 0 then<br> FConnObj.Tag := 1; //设置为使用标识。<br> FAStart := now; //设置启用时间 。<br>end;<br>end;</p>
<p>function tdacon.GetUseFlag: Boolean;<br>begin<br>Result := (FConnObj.Tag > 0); //Tag=0表示闲置,Tag>0表示在使用。<br>end;<br>{ TDACPool }</p>
<p>constructor TDACPool.Create(const MaxNumBer: Integer; FreeMinutes: Integer = 60;<br>TimerTime: Integer = 5000);<br>begin<br>//InitializeCriticalSection(FSection);<br>FPOOLNUMBER := MaxNumBer; //设置池大小<br>FPollingInterval := FreeMinutes; // 连接池中 FPollingInterval 以上没用的 自动回收连接池<br>FList := TList.Create;<br>FTime := TTimer.Create(nil);<br>FTime.Enabled := False;<br>FTime.Interval := TimerTime; //5秒检查一次<br>FTime.OnTimer := OnMyTimer;<br>FTime.Enabled := True;<br>end;</p>
<p>destructor TDACPool.Destroy;<br>var<br>i: integer;<br>begin<br>FTime.OnTimer := nil;<br>FTime.Free;<br>for i := FList.Count - 1 downto 0 do<br>begin<br> try<br> FDACon := TDAcon(FList.Items);<br> if Assigned(FDACon) then<br> FreeAndNil(FDACon);<br> FList.Delete(i);<br> except<br> end;<br>end;<br>FList.Free;<br>//DeleteCriticalSection(FSection);<br>inherited;<br>end;</p>
<p>procedure TDACPool.Enter;<br>begin<br>//EnterCriticalSection(FSection);<br>if Assigned(Self) then<br> MonitorEnter(Self);<br>end;</p>
<p>procedure TDACPool.Leave;<br>begin<br>//LeaveCriticalSection(FSection);<br>if Assigned(Self) then<br> MonitorExit(Self);<br>end;</p>
<p>//根据字符串连接参数 取出当前连接池可以用的tdaconnection</p>
<p>function TDACPool.GetCon(const tmpConfig: TDAConfig): TFDConnection;<br>var<br>i: Integer;<br>IsResult: Boolean; //标识<br>CurOutTime: Integer;<br>begin<br>Result := nil;<br>IsResult := False;<br>CurOutTime := 0;<br>Enter;<br>try<br> for i := 0 to FList.Count - 1 do<br> begin<br> FDACon := TDACon(FList.Items);<br> if not FDACon.UseFlag then //可用<br> //if SameConfig(tmpConfig, FDACon) then //找到<br> begin<br> FDACon.UseFlag := True; //标记已经分配用了<br> Result := FDACon.ConnObj;<br> IsResult := True;<br> Break; //退出循环<br> end;<br> end; // end for<br>finally<br> Leave;<br>end;<br>if IsResult then<br> Exit;<br>//池未满 新建一个<br>Enter;<br>try<br> if FList.Count < FPOOLNUMBER then //池未满<br> begin<br> FDACon := tdacon.Create(tmpConfig);<br> FDACon.UseFlag := True;<br> Result := FDACon.ConnObj;<br> IsResult := True;<br> FList.Add(FDACon); //加入管理队列<br> end;<br>finally<br> Leave;<br>end;<br>if IsResult then<br> Exit;<br>//池满 等待 等候释放<br>while True do<br>begin<br> Enter;<br> try<br> for i := 0 to FList.Count - 1 do<br> begin<br> FDACon := tdacon(FList.Items);<br> //if SameConfig(tmpConfig, FDACon) then //找到<br> if not FDACon.UseFlag then //可用<br> begin<br> FDACon.UseFlag := True; //标记已经分配用了<br> Result := FDACon.ConnObj;<br> IsResult := True;<br> Break; //退出循环<br> end;<br> end; // end for<br> if IsResult then<br> Break; //找到退出<br> finally<br> Leave;<br> end;<br> //如果不存在这种字符串的池子 则 一直等到超时<br> if CurOutTime >= 5000 * 6 then //30s<br> begin<br> raise Exception.Create('未找到可用的连接!连接超时!');<br> Break;<br> end;<br> Sleep(500); //0.5秒钟<br> CurOutTime := CurOutTime + 500; //超时设置成30秒<br>end; //end while<br>end;</p>
<p>procedure TDACPool.PutCon(const DAConnection: TFDConnection);<br>var<br>i: Integer;<br>begin<br>{<br>if not Assigned(DAConnection) then Exit;<br>try<br>Enter;<br>DAConnection.Tag := 0; //如此应该也可以 ,未测试...<br>finally<br>Leave;<br>end;<br>}<br>Enter; //并发控制<br>try<br> for i := FList.Count - 1 downto 0 do<br> begin<br> FDACon := tdacon(FList.Items);<br> if FDACon.ConnObj = DAConnection then<br> begin<br> FDACon.UseFlag := False;<br> Break;<br> end;<br> end;<br>finally<br> Leave;<br>end;<br>end;</p>
<p>procedure TDACPool.FreeConnection;<br>var<br>i: Integer;</p>
<p>function MyMinutesBetween(const ANow, AThen: TDateTime): Integer;<br>begin<br> Result := Round(MinuteSpan(ANow, AThen));<br>end;</p>
<p>begin<br>Enter;<br>try<br> for i := FList.Count - 1 downto 0 do<br> begin<br> FDACon := tdacon(FList.Items);<br> if MyMinutesBetween(Now, FDACon.AStart) >= FPollingInterval then //释放池子许久不用的DAC<br> begin<br> FreeAndNil(FDACon);<br> FList.Delete(i);<br> end;<br> end;<br>finally<br> Leave;<br>end;<br>end;</p>
<p>procedure TDACPool.OnMyTimer(Sender: TObject);<br>begin<br>FreeConnection;<br>end;</p>
<p>function TDACPool.SameConfig(const Source: TDAConfig; Target: TDACon): Boolean;<br>begin<br>//考虑到支持多数据库连接,需要本方法做如下等效连接判断.如果是单一数据库,可忽略本过程。<br>{ Result := False;<br>if not Assigned(Source) then Exit;<br>if not Assigned(Target) then Exit;<br>Result := SameStr(LowerCase(Source.ConnectionName),LowerCase(Target.ConnObj.Name));<br>Result := Result and SameStr(LowerCase(Source.DriverName),LowerCase(Target.ConnObj.Provider));<br>Result := Result and SameStr(LowerCase(Source.HostName),LowerCase(Target.ConnObj.Properties['Data Source'].Value));<br>Result := Result and SameStr(LowerCase(Source.DataBase),LowerCase(Target.ConnObj.Properties['Initial Catalog'].Value));<br>Result := Result and SameStr(LowerCase(Source.UserName),LowerCase(Target.ConnObj.Properties['User ID'].Value));<br>Result := Result and SameStr(LowerCase(Source.PassWord),LowerCase(Target.ConnObj.Properties['Password'].Value));<br>//Result := Result and (Source.OSAuthentication = Target.ConnObj.OSAuthentication);<br>}<br>end;</p>
<p>function TDACPool.GetConnectionCount: Integer;<br>begin<br>Result := FList.Count;<br>end;<br>//初始化时创建对象</p>
<p>initialization<br>DAConfig := TDAConfig.Create(ChangeFileExt(ParamStr(0), '.ini'));<br>DACPool := TDACPool.Create(PoolNum);</p>
<p>finalization<br>if Assigned(DACPool) then<br> DACPool.Free;<br>if Assigned(DAConfig) then<br> DAConfig.Free;</p>
<p>end.</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/Yang-YaChao/p/15061341.html
頁:
[1]