《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 其他 > 業(yè)界動(dòng)態(tài) > 數(shù)據(jù)庫(kù)遠(yuǎn)程數(shù)據(jù)上報(bào)策略及實(shí)現(xiàn)

數(shù)據(jù)庫(kù)遠(yuǎn)程數(shù)據(jù)上報(bào)策略及實(shí)現(xiàn)

2009-10-15
作者:鄧其軍1, 牛曉太1, 余小鵬1

??? 摘??要: 提出了一種數(shù)據(jù)庫(kù)遠(yuǎn)程數(shù)據(jù)上報(bào)的策略,,并對(duì)該策略的程序?qū)崿F(xiàn)過(guò)程作了介紹,。

??? 關(guān)鍵詞: 遠(yuǎn)程數(shù)據(jù)? 上報(bào)? 數(shù)據(jù)壓縮

?

  在很多數(shù)據(jù)庫(kù)應(yīng)用程序中,都要用到數(shù)據(jù)遠(yuǎn)程上報(bào)的功能,,如人口普查,、城市危險(xiǎn)源及事故普查、各種考試數(shù)據(jù)上報(bào)等,。這些應(yīng)用程序都需要將各下級(jí)部門(mén)的特定數(shù)據(jù)提取出來(lái),,通過(guò)各種方式上報(bào)到上級(jí)部門(mén),,再由上級(jí)部門(mén)進(jìn)行匯總,。上級(jí)部門(mén)在進(jìn)行數(shù)據(jù)匯總時(shí),有時(shí)候只需要考慮新數(shù)據(jù)的插入問(wèn)題,。如養(yǎng)路費(fèi)征收IC卡網(wǎng)絡(luò)管理系統(tǒng),,此時(shí)下級(jí)的每條數(shù)據(jù)記錄是一次輸入的,,在數(shù)據(jù)上報(bào)之后不會(huì)發(fā)生已經(jīng)輸入的數(shù)據(jù)記錄在下級(jí)被修改,,從而上級(jí)也要發(fā)生相應(yīng)修改的情況,。此時(shí),,用該文提到的用BulkCopy方法就可以滿(mǎn)足其需要,。但是有的情況下,,上級(jí)部門(mén)的數(shù)據(jù)匯總必須考慮下級(jí)數(shù)據(jù)所有的變化情況(新數(shù)據(jù)的插入、已有數(shù)據(jù)記錄的修改,、已有數(shù)據(jù)記錄的刪除),。此時(shí),用BulkCopy方法就無(wú)法對(duì)數(shù)據(jù)進(jìn)行修改與刪除了。除非在數(shù)據(jù)上報(bào)時(shí),,下級(jí)部門(mén)將其所有數(shù)據(jù)都拷貝一份上傳,;上級(jí)部門(mén)在數(shù)據(jù)接收時(shí),,將該下級(jí)部門(mén)的歷史數(shù)據(jù)全部刪除,,再導(dǎo)入其數(shù)據(jù),,才能保證與下級(jí)的數(shù)據(jù)的一致性。顯然,,這樣的處理方式,必然導(dǎo)致數(shù)據(jù)的傳輸及處理量大增,,而且很多都是做無(wú)用功,特別是在很多情況下需要用電話(huà)撥號(hào)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)傳輸?shù)臅r(shí)候,,其效率非常低,。

1? 總體策略

  在作者參與開(kāi)發(fā)的“城市重大危險(xiǎn)源普查及事故管理系統(tǒng)”中,其下級(jí)部門(mén)為各企業(yè),,上級(jí)部門(mén)為政府安全生產(chǎn)管理部門(mén)。在該系統(tǒng)中,,企業(yè)定期向政府部門(mén)上報(bào)相關(guān)的危險(xiǎn)源及事故信息,。其中危險(xiǎn)源是指企業(yè)各種鍋爐壓力容器,、加油站等可能發(fā)生危險(xiǎn)的地點(diǎn)分布情況。這些危險(xiǎn)源信息可能被增加、修改或刪除,。系統(tǒng)開(kāi)發(fā)語(yǔ)言為VC++6.0,,企業(yè)端數(shù)據(jù)庫(kù)為Access或SQL Server,政府端數(shù)據(jù)庫(kù)為SQL Server,,用OLE DB方式連接數(shù)據(jù)庫(kù),,用嵌入式SQL Server語(yǔ)言直接操作數(shù)據(jù)庫(kù)數(shù)據(jù)。上下級(jí)之間的數(shù)據(jù)傳輸方式為軟盤(pán),、郵件和FTP三種方案,。本系統(tǒng)主要采用了數(shù)據(jù)庫(kù)日志及數(shù)據(jù)壓縮技術(shù),盡可能地減少數(shù)據(jù)傳送量,。

  數(shù)據(jù)庫(kù)日志就是在用VC的嵌入式SQL Server語(yǔ)言進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),,將SQL Server腳本經(jīng)過(guò)適當(dāng)?shù)霓D(zhuǎn)換后記錄在一個(gè)數(shù)據(jù)庫(kù)日志表(pubTbDBLog)中。上報(bào)數(shù)據(jù)時(shí)只需要提取pubTbDBLog表的部分內(nèi)容,。政府端接收后,,按順序執(zhí)行上報(bào)的SQL Server腳本,即能實(shí)現(xiàn)與企業(yè)端的數(shù)據(jù)完全一致,。

數(shù)據(jù)上報(bào)與接收的流程如圖1所示,。

?

?

2?數(shù)據(jù)庫(kù)日志操作

  數(shù)據(jù)庫(kù)日志操作的目的是保存SQL腳本,即將企業(yè)端對(duì)數(shù)據(jù)庫(kù)的操作記錄下來(lái),,存放在數(shù)據(jù)庫(kù)日志記錄表pubTbDBLog(nId,,strTable,strSQL,,strOperType,,strGuid,dtOper,,beUped)中,。其中nId為主鍵,自動(dòng)增量,;strTable為SQL操作的數(shù)據(jù)庫(kù)表名,;strSQL為對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作的腳本;strOperType為操作類(lèi)型,,包括插入,、修改、刪除三種,;strGuid為一個(gè)GUID值(全球惟一ID號(hào),,長(zhǎng)度為32位字符),用來(lái)惟一標(biāo)識(shí)一條記錄,;dtOper為操作時(shí)間,,取每條記錄生成(即對(duì)數(shù)據(jù)庫(kù)的每一次操作)的當(dāng)前時(shí)間,;beUped標(biāo)識(shí)當(dāng)前記錄是否已經(jīng)上報(bào)過(guò)。

2.1 數(shù)據(jù)庫(kù)操作的要求

  在本系統(tǒng)中,,當(dāng)對(duì)需要上報(bào)數(shù)據(jù)的表進(jìn)行操作時(shí),,必須滿(mǎn)足如下要求:

  (1)數(shù)據(jù)庫(kù)記錄的修改(包括添加、刪除,、修改)必須在程序中直接用嵌入式SQL腳本實(shí)現(xiàn),。

  (2)執(zhí)行數(shù)據(jù)庫(kù)操作必須使用一個(gè)全局函數(shù)ExecuteSQLCmd(CString strCmd),其中strCmd為執(zhí)行數(shù)據(jù)庫(kù)操作的SQL腳本,。該函數(shù)將腳本寫(xiě)入pubTbDBLog表,。

2.2 保存SQL腳本的過(guò)程說(shuō)明

  下面以企業(yè)端用戶(hù)向危險(xiǎn)源記錄表rsiTbSource(nID,,strEnNo,,strName,strSite,,strRank,,strType,dtSetUp)中插入一條危險(xiǎn)源記錄為例,,說(shuō)明保存SQL腳本的操作過(guò)程,。

  (1)用戶(hù)通過(guò)對(duì)話(huà)界面輸入危險(xiǎn)源信息,其中strEnNo表示企業(yè)編號(hào),,strName表示危險(xiǎn)源名稱(chēng),,strSite表示危險(xiǎn)源位置,strRank表示危險(xiǎn)源等級(jí),,strType表示危險(xiǎn)源類(lèi)型,,dtSetUp表示危險(xiǎn)源建立日期。另外nID是一個(gè)自動(dòng)增量,,作為主鍵標(biāo)識(shí),,沒(méi)有具體意義。rsiTbSource表除了以上字段外,,還有其他字段,,本處為簡(jiǎn)化而省略。

  (2)用戶(hù)輸入信息完畢,,點(diǎn)擊“保存”命令按鈕,,系統(tǒng)將用戶(hù)輸入的信息拼成一條SQL腳本,如:CString strCmd=INSERT INTO rsiTbSource(strEnNo,,strName,,strSite,strRank,,strType,,dtSetUp)VALUES(‘420124098987001’,,‘熱水鍋爐’,‘武漢市武昌區(qū)武漢大學(xué)二區(qū)’,,‘二級(jí)’,,‘鍋爐壓力容器’,‘2003-7-21’),。

  (3)系統(tǒng)調(diào)用ExecuteSQLCmd函數(shù),,包括以下(4)、(5),、(6)的內(nèi)容,。

  (4)對(duì)strCmd進(jìn)行解析,同時(shí)生成一個(gè)32位的GUID值,,將strCmd修改為strCmd=INSERT INTO rsiTbSource(strEnNo,,strName,strSite,,strRank,,strType,dtSetUp,,strGuid)VALUES(‘420124098987001’,,‘熱水鍋爐’,‘武漢市武昌區(qū)武漢大學(xué)二區(qū)’,,‘二級(jí)’,,‘鍋爐壓力容器’,‘2003-7-21’,,‘ed32wq3ddvervgjl6tgj8fjFFVBfgwgw’),。

  (5)執(zhí)行腳本命令(不使用ExecuteSQLCmd函數(shù))。

  (6)如果第(5)步執(zhí)行成功,,則向pubDBLog表插入一條記錄(strTbSource,,strCmd,i,,ed32wq3ddvervgjl6tgj8fjFFVBfgwgw,,2003-7-21,0),,其中的strCmd是第(4)步中strCmd的所有字符,。

3? 數(shù)據(jù)上報(bào)

  數(shù)據(jù)上報(bào)是將pubTbDBLog中符合條件的記錄提取出來(lái),進(jìn)行壓縮后傳給上級(jí),。

3.1 上報(bào)數(shù)據(jù)提取

  在提取數(shù)據(jù)前要對(duì)pubTbDBLog表中的記錄進(jìn)行一些預(yù)處理,。由于每次對(duì)需要上報(bào)的數(shù)據(jù)庫(kù)表的操作都被記錄在了pubTbDBLog表中,有些記錄(為了方便,,稱(chēng)pubTbDBLog表中的一條記錄為“記錄”,,稱(chēng)需要上報(bào)的數(shù)據(jù)表中的一條記錄為“數(shù)據(jù)”)是不必要的,,上報(bào)之前需要進(jìn)行簡(jiǎn)化。例如:向數(shù)據(jù)庫(kù)表中插入一條數(shù)據(jù),,后來(lái)對(duì)該數(shù)據(jù)進(jìn)行了若干次修改,,最后刪除該條數(shù)據(jù)。此時(shí),,pubTbDBLog中有三個(gè)以上與這條數(shù)據(jù)相關(guān)的記錄(它們?cè)趐ubTbDBLog表中的strGuid字段值相同),,其strOperType值分別是“i”、“u”,、“d”,。如果這三個(gè)記錄都被上報(bào),并在政府端被先后執(zhí)行,,其結(jié)果還是沒(méi)有該條數(shù)據(jù),,白白浪費(fèi)了執(zhí)行三次SQL命令的時(shí)間。

因此,,如果與某個(gè)strGuid值相關(guān)的數(shù)據(jù)最后被刪除,,則在政府端只需要執(zhí)行一次刪除操作,,即與該strGuid值相關(guān)的pubTbDBLog表中的記錄只需要上報(bào)一條刪除的操作即可,。實(shí)現(xiàn)對(duì)這種情況的pubTbDBLog表簡(jiǎn)化的SQL腳本如下:

  DELETE FROM pubTbDBLog WHERE strOperType <> ′d′

  AND strGuid IN(SELECT DISTINCT a.strGuid

  FROM pubTbDBLog a WHERE a.strOperType=′d′)

  完成簡(jiǎn)化后,即可將pubTbDBLog中符合條件(提取數(shù)據(jù)的條件是:未曾上報(bào)過(guò)的數(shù)據(jù)或指定時(shí)間范圍內(nèi)的數(shù)據(jù))的數(shù)據(jù)提取出來(lái)放入一個(gè)文件中,。存放導(dǎo)出數(shù)據(jù)的文件可以是Access 數(shù)據(jù)庫(kù)表,,或者是文本文件。作者用的是Access數(shù)據(jù)庫(kù)表,,它經(jīng)過(guò)壓縮解壓縮后能在政府端直接取Access表中的SQL腳本執(zhí)行,;也可以用文本文件,但上報(bào)時(shí)需要將符合條件的pubTbDBLog表記錄放入一個(gè)臨時(shí)文件,,再用bulkCopy的方法存入文本文件,。在政府端用bulkInsert的方法向一個(gè)與pubTbDBLog相同結(jié)構(gòu)的表導(dǎo)入數(shù)據(jù),再執(zhí)行該表的記錄中的SQL腳本,。

3.2 數(shù)據(jù)文件壓縮

  通常情況下,,企業(yè)端向政府端報(bào)送數(shù)據(jù)是經(jīng)過(guò)電話(huà)撥號(hào)網(wǎng)絡(luò)進(jìn)行的,其傳輸速率較低,。因此,,有必要對(duì)存放導(dǎo)出數(shù)據(jù)的Access文件或文本文件進(jìn)行壓縮后再傳遞。本系統(tǒng)使用了WinZip的數(shù)據(jù)壓縮與解壓縮接口,。其過(guò)程如下(假定字符串filepathname指向需要壓縮的文件):

  (1)獲取文件路徑及文件名信息,。

  int nPos,length,,div,;

  CString filepathtitle,,filename;

  nPos=filepathname.ReverseFind(′.′),;

  filepathtitle=filepathname.Left(nPos)

  /*去掉擴(kuò)展名后的文件名,,帶路徑*/

  length=filepathname.GetLength( );

  div=filepathname.ReverseFind(′\\′),;

  filename=filepathname.Right(length-div-1),;/*文件名,不帶路徑*/

  (2)創(chuàng)建壓縮文件實(shí)例,。

  CZipFile zf(filepathtitle+″.cmp″,,0);

  char buf[BUF_SIZE],;//BUF_SIZE=2048

  CFile f(filepathname,,CFile∷modeRead);

  zip_fileinfo zi,;

  zf.UpdateZipInfo(zi,,f);

  (3)向壓縮文件實(shí)例讀入數(shù)據(jù),。

  zf.OpenNewFileInZip(filename,,zi,Z_BEST_COMPRESSION),;

  int size_read,;

  do

  {

  ?????? size_read=f.Read(buf,BUF_SIZE),;

????  ?? if (size_read)

?????? ?  ? zf.WriteInFileInZip(buf,,size_read);

  }

  while (size_read==BUF_SIZE),;

  zf.Close( ),;//關(guān)閉壓縮文件實(shí)例

  經(jīng)測(cè)試,壓縮文件的大小約為原文件大小的1/5~1/10,,效果較好,。

4? 數(shù)據(jù)接收

  政府端數(shù)據(jù)接收的工作包括三個(gè)步驟:選擇文件、解壓縮,、導(dǎo)入數(shù)據(jù),。

4.1 選擇數(shù)據(jù)文件

  對(duì)應(yīng)于企業(yè)端通過(guò)磁盤(pán)和郵件上報(bào)的數(shù)據(jù),政府端首先需要將其存放到本地計(jì)算機(jī)的硬盤(pán)上,,再進(jìn)行數(shù)據(jù)文件選擇和接收,。

選擇文件時(shí),調(diào)用打開(kāi)文件對(duì)話(huà)框,,再由用戶(hù)選定一個(gè)或多個(gè)指定類(lèi)型(*.cmp)的文件,。對(duì)于每一個(gè)選中的文件,,系統(tǒng)對(duì)其執(zhí)行解壓縮和導(dǎo)入數(shù)據(jù)的操作。

4.2 解壓縮

  與前面所述的文件壓縮一樣,,解壓縮與采用了WinZip提供的接口,。其過(guò)程如下:

  (1)創(chuàng)建解壓縮文件實(shí)例,并用選定的壓縮文件初始化,。

  CUnzipFile uf(m_strCmpFile),;/*m_strCmpFile為選定的壓縮文件名*/

  (2)獲取壓縮文件中被壓縮前的文件信息。

  /*指向壓縮文件中的第一個(gè)文件(一個(gè)壓縮文件可以由多個(gè)文件壓縮而成,,本系統(tǒng)只有一個(gè))*/

  uf.GoToFirstFile( )

  unz_file_info ui,;/*用于管理解壓縮文件信息的一個(gè)結(jié)構(gòu)*/

  /*獲取壓縮文件中當(dāng)前文件被壓縮前的信息,如文件名大小*/

  uf.GetCurrentFileInfo(&ui),;

  int iNameSize=ui.size_filename+1,;

  char*pName=new char[iNameSize];

  uf.GetCurrentFileInfo(NULL,,pName,,iNameSize);//獲取文件名

  TCHAR szDir[_MAX_DIR],;

  TCHAR szDrive[_MAX_DRIVE],;

  _tsplitpath(m_strUnCmpFile,szDrive,,szDir,,NULL,,NULL),;

  CString szPath=CString(szDrive)+szDir;

  m_strMovedDB=szPath+pName,;/*解壓縮后,,存放文件的路徑與文件名*/

  CFile f(m_strMovedDB,CFile∷modeWrite | CFile∷modeCreate),;

  delete[ ] pName,;

  (3)解壓縮。

  uf.OpenCurrentFile( ),;

  char buf[BUF_SIZE],;

  int size_read;

  do

  {

  ?????? size_read=uf.ReadCurrentFile(buf,,BUF_SIZE),;

????  ?? if(size_read>0)

?????? ?  f.Write(buf,size_read),;

  }

  while(size_read==BUF_SIZE),;

  uf.UpdateFileStatus(f,,ui);? /*還原文件的原來(lái)的日期和其他屬性*/

  uf.Close( ),;

4.3 導(dǎo)入數(shù)據(jù)

  從一個(gè)被解壓縮后生成的Access數(shù)據(jù)庫(kù)向政府端數(shù)據(jù)庫(kù)導(dǎo)入數(shù)據(jù)的過(guò)程為:連接該Access數(shù)據(jù)庫(kù),;按先后順序從該數(shù)據(jù)庫(kù)表pubTbDBLog中提取記錄;執(zhí)行該條記錄的SQL腳本,。下面只對(duì)SQL腳本的執(zhí)行進(jìn)行說(shuō)明,。

對(duì)于刪除和修改操作,SQL腳本可以直接執(zhí)行,。因?yàn)槿绻蠄?bào)了重復(fù)的數(shù)據(jù),,即使某條記錄已經(jīng)被刪除或修改,再執(zhí)行一次同樣的刪除或修改操作,,SQL命令的執(zhí)行也不會(huì)造成語(yǔ)法錯(cuò)誤或數(shù)據(jù)錯(cuò)誤,。

  對(duì)于插入操作,SQL腳本則不能直接執(zhí)行,。因?yàn)槿绻蠄?bào)了重復(fù)的數(shù)據(jù),,則直接執(zhí)行插入會(huì)使數(shù)據(jù)庫(kù)中存在二條同樣的數(shù)據(jù)。因此,,先要執(zhí)行一次刪除操作,,將對(duì)應(yīng)的數(shù)據(jù)刪除(由于pubTbDBLog表中有二個(gè)字段記錄了SQL腳本對(duì)應(yīng)的表名和GUID值,刪除操作很容量執(zhí)行),。即使該數(shù)據(jù)不存在,,SQL命令的執(zhí)行也不會(huì)造成語(yǔ)法錯(cuò)誤或數(shù)據(jù)錯(cuò)誤。

5? 結(jié)? 論

  本文討論的基于數(shù)據(jù)庫(kù)操作日志和數(shù)據(jù)壓縮的數(shù)據(jù)上報(bào)與接收技術(shù),,有著很強(qiáng)的通用性,。對(duì)于任何一個(gè)應(yīng)用系統(tǒng),只要在數(shù)據(jù)庫(kù)中建立一個(gè)數(shù)據(jù)庫(kù)日志表,,并且下級(jí)端執(zhí)行數(shù)據(jù)庫(kù)操作時(shí)滿(mǎn)足2.1中提及的二個(gè)條件,,就能使用。特別是對(duì)于需要上傳的數(shù)據(jù)涉及的表較多,、下級(jí)端對(duì)數(shù)據(jù)經(jīng)常需要修改,、上下級(jí)數(shù)據(jù)要求較高度的一致性的情況,其優(yōu)點(diǎn)更加明顯,。

  本系統(tǒng)的數(shù)據(jù)上報(bào)與接收策略也有一些不足之處,。例如,企業(yè)端pubTbDBLog表中數(shù)據(jù)的導(dǎo)出,,可能用bulkCopy效率更高,;數(shù)據(jù)導(dǎo)出與接收時(shí),暫時(shí)還沒(méi)有使用多線(xiàn)程技術(shù)等。這些都需要在以后的工作中進(jìn)一步完善,。

參考文獻(xiàn)

1 閻宇馳,,倪津.SQL Server數(shù)據(jù)庫(kù)遠(yuǎn)程數(shù)據(jù)上報(bào)策略及其應(yīng)用研究.山西交通科技,2002,;(2)

2 羅琨,,陳奇.連鎖店MIS中多數(shù)據(jù)庫(kù)數(shù)據(jù)通信的設(shè)計(jì)和實(shí)現(xiàn).計(jì)算機(jī)應(yīng)用研究,2000,;(6)

3 薩師宣,,王珊.數(shù)據(jù)庫(kù)系統(tǒng)概論.北京:高等教育出版社,1999

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,,并不代表本網(wǎng)站贊同其觀點(diǎn)。轉(zhuǎn)載的所有的文章,、圖片,、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無(wú)法一一聯(lián)系確認(rèn)版權(quán)者,。如涉及作品內(nèi)容,、版權(quán)和其它問(wèn)題,請(qǐng)及時(shí)通過(guò)電子郵件或電話(huà)通知我們,,以便迅速采取適當(dāng)措施,,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話(huà):010-82306118,;郵箱:[email protected],。