很久沒有寫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/