很久没有写DIOCP的Demo了,主要公司的事情太繁琐,工作之余都不想动了,之前承若的群里面朋友们的DEMO,昨天晚上恶补了一下,把对数据库连接池的操作加入到了Demo中,大家可以通过SVN下载到最新的代码和Demo。
好了我带大家看看这次的DEMO,经过群里面朋友们的推荐,这次代码中引用了UntCobblerUniPool连接池代码来完成的本次的DEMO,研究了下代码,里面使用的线程时钟来做死连和多余连接的释放。感谢UntCobblerUniPool作者无私奉献的精神。
先截个图,看看服务端的界面。
主要加入了多帐套的连接的配置。配置文件存放在config\dbpool.config,是一个json格式的文件配置
{
"account2013": {
"connString": "Provider Name=SQL Server;Data Source=192.168.1.2;Database=xxxx;User ID=sa;Password=sa"
},
"account2012": {
"connString": "Provider Name=SQL Server;Data Source=192.168.1.2;Database=xxx02;User ID=sa;Password=sa"
}
}
DEMO中我演示了两个帐套(实际运行中帐套个数是不固定),account2013和account2012代表帐套的ID,在clientContext中可以通过客户端传递过来的帐套ID,获取连接字符串,到连接池中获取一个连接。
看看服务端的代码
procedure TClientContext.dataReceived(const pvDataObject:TObject); var lvJsonStream:TJSonStream; lvFile:String; lvCmdIndex:Cardinal; lvXMLData, lvEncodeData:AnsiString; lvSQL, lvID:String; lvDBDataOperator:TUniOperator; lvPoolObj:TUniCobbler; begin lvJsonStream := TJSonStream(pvDataObject); try lvCmdIndex := lvJsonStream.JSon.I['cmdIndex']; //执行SQL的命令ID if lvCmdIndex= 1001 then begin //客户端传递过来的帐套ID lvID := lvJsonStream.Json.S['config.accountID']; if lvID = '' then begin raise Exception.Create('没有指定帐套ID(config.accountID)'); end; //客户端指定要执行的SQL lvSQL := lvJsonStream.Json.S['script.sql']; if lvSQL = '' then begin raise Exception.Create('没有指定要执行的SQL!'); end; //通过帐套ID获取一个连接池对象 lvPoolObj := TUniPool.getConnObject(lvID); try //打开连接 lvPoolObj.checkConnect; //Uni数据库操作对象<可以改用对象池效率更好> lvDBDataOperator := TUniOperator.Create; try //设置使用的连接池 lvDBDataOperator.Connection := lvPoolObj.ConnObj; self.StateINfo := '借用了一个lvADOOpera,准备打开连接!'; try //获取一个查询的数据 lvXMLData := lvDBDataOperator.CDSProvider.QueryXMLData(lvSQL); self.StateINfo := 'lvADOOpera,执行SQL语句完成,准备回写数据'; except raise; end; lvJsonStream.Clear(); lvJsonStream.Stream.WriteBuffer(lvXMLData[1], Length(lvXMLData)); lvJsonStream.setResult(True); finally lvDBDataOperator.Free; end; finally //归还连接池 TUniPool.releaseConnObject(lvPoolObj); end; //回写数据给客户端 writeObject(lvJsonStream); end else begin //返回数据 writeObject(lvJsonStream); end; except on E:Exception do begin lvJsonStream.Clear(); lvJsonStream.setResult(False); lvJsonStream.setResultMsg(e.Message); writeObject(lvJsonStream); end; end; end;
注释写的比较清楚了,我就不再解释了,其他关联代码可以具体去看各单元的代码。
看看客户端界面。
客户端通过指定帐套ID,告诉服务端应该选用哪个数据库进行操作。
客户端执行的代码
procedure TfrmMain.btnOpenSQLClick(Sender: TObject); var lvRecvObj, lvSendObj:TJsonStream; i, l, lvSize:Integer; lvData:AnsiString; begin lvSendObj := TJsonStream.Create; lvRecvObj := TJsonStream.Create; try lvSendObj.Clear(); //帐套ID lvSendObj.Json.S['config.accountID'] := txtAccount.Text; //执行SQL的命令ID lvSendObj.Json.I['cmdIndex'] := 1001; //要执行的SQL lvSendObj.Json.S['script.sql'] := mmoSQL.Lines.Text; //发送到服务端进行处理<使用Indy进行传输>,如果需要使用ICS,可以在IOCPCoder文件夹中找到对应的uICSClientJSonStreamCoder.pas单元 TIdTcpClientJSonStreamCoder.Encode(self.IdTCPClient, lvSendObj); //接收服务端处理的数据<使用Indy接收数据> TIdTcpClientJSonStreamCoder.Decode(self.IdTCPClient, lvRecvObj); if not lvRecvObj.getResult then begin raise Exception.Create(lvRecvObj.getResultMsg); end; //获取数据 SetLength(lvData, lvRecvObj.Stream.Size); lvRecvObj.Stream.Position := 0; lvRecvObj.Stream.ReadBuffer(lvData[1], lvRecvObj.Stream.Size); //放入CDS的XMLDATA cdsMain.XMLData := lvData; finally lvSendObj.Free; lvRecvObj.Free; end; end;
在DIOCP\Demos\IOCPCoder代码中我写了一些客户端的界面和编码器,有ICS,和Indy的,有需要的朋友可以直接引用使用。
基本上差不多了。刚刚群里面的朋友测试在XE4下面测试是通过的,我的环境是D2007。
>>>>>>DIOCP讨论群:320641073
>>>>>>SVN源码和DEMO下载:https://code.google.com/p/diocp/