(本文所讨论的开发环境,为 Delphi XE5)本篇介绍如何实现服务器端数据库连接的共享。 常见的数据库连接实现,是为每个数据模块建立一个连接。但这样做将产生大量的数据库连接,并产生很多问题。 在上一篇,我们分析了 Datasnap 客户端连接服务器端时相关事件的执行顺序。其中,ServerContainerUnit1 容器是在服务器端一开始运行时就创建,直到服务器端关闭、停止服务时才结束。因此,我们可以在容器对象生成时,创建一个数据库连接列表,用于保存为每个客户端创建的数据库连接对象,该列表对象在容器销毁时销毁;并在容器中实现了一个获取数据库连接的方法。 下面以 TADOConnection 为例,数据库连接列表 ConnectionList 的定义如下: type TServerContainer1 = class(TDataModule) ...... private { Private declarations } ConnectionList: TDictionary<Integer, TADOConnection>; public //获取数据库连接对象 //参数:(如果不存在则新建) CreateNewIfNotExist function GetConnection(CreateNewIfNotExist: Boolean = True): TADOConnection; ...... 创建 ConnectionList 对象: procedure TServerContainer1.DataModuleCreate(Sender: TObject); begin ConnectionList := TDictionary<Integer, TADOConnection>.Create; end; 销毁 ConnectionList 对象: procedure TServerContainer1.DataModuleDestroy(Sender: TObject); begin ConnectionList.Free; end; 获取数据库连接的思路是:如果当前客户端的数据库连接已经存在,则直接从 ConnectionList 里取出;如果不存在,根据参数 CreateNewIfNotExist 判断是否创建;如果创建,则创建一个新连接,并将连接保存到 ConnectionList 中。ConnectionList 中的 Key 值为客户端连接时的线程ID。 代码如下: function TServerContainer1.GetConnection(CreateNewIfNotExist: Boolean): TADOConnection; var dbConn: TADOConnection; begin Result := nil; if ConnectionList.ContainsKey(TDSSessionManager.GetThreadSession.Id) then begin Result := ConnectionList[TDSSessionManager.GetThreadSession.Id]; end else if CreateNewIfNotExist then begin dbConn := TADOConnection.Create(nil); dbConn.ConnectionString := csConnectionString; dbConn.LoginPrompt := False; ConnectionList.Add(TDSSessionManager.GetThreadSession.Id, dbConn); Result := dbConn; end; end; 当客户端断开连接时,要同时释放该客户端的数据库连接,以防止内存泄露。 procedure TServerContainer1.DSServer1Disconnect(DSConnectEventObject: TDSConnectEventObject); var dbConn: TADOConnection; begin if ConnectionList.ContainsKey(TDSSessionManager.GetThreadSession.Id) then begin //如果实例存在 dbConn := ConnectionList[TDSSessionManager.GetThreadSession.Id]; ConnectionList.Remove(TDSSessionManager.GetThreadSession.Id); dbConn.Free; end; end; 为了防止客户端过多导致数据库连接被使用完毕造成错误,建议一定要开启数据库的连接池功能,以便让所有的客户端都分享数据库连接;而在编写服务方法时,请在执行前打开连接,在方法执行完毕后关闭连接(注意,是关闭连接,而不是释放数据库连接对象)。