FireBird編程從入門到精通

從來(lái)沒(méi)有過(guò)這么一種數(shù)據(jù)庫(kù)折汞,能夠像InterBase/FireBird一樣富有激情。這是一種完全為程序員準(zhǔn)備的數(shù)據(jù)庫(kù)盖腿,就像瑞士軍刀一樣小巧爽待、方便、實(shí)用翩腐。以往的數(shù)據(jù)庫(kù)鸟款,不是太大太笨重(例如,Oracle茂卦、MS SQL何什、DB2),就是太簡(jiǎn)陋等龙,功能不足(例如My SQL)处渣。而InterBase/FireBird則是在兩者之間找到了一個(gè)很好的平衡點(diǎn)伶贰,筆者不妨稱之為“中型數(shù)據(jù)庫(kù)”。隨著硬件環(huán)境的不斷發(fā)展罐栈,普通的個(gè)人電腦的計(jì)算能力越來(lái)越逼近并不太久以前的大型計(jì)算機(jī)的能力黍衙,這種趨勢(shì)同時(shí)也大大推動(dòng)了與此相適應(yīng)的中型數(shù)據(jù)庫(kù)的應(yīng)用。中型數(shù)據(jù)庫(kù)逐漸蠶食大型數(shù)據(jù)庫(kù)的市場(chǎng)荠诬,這幾乎是一個(gè)明顯的趨勢(shì)琅翻。隨著軟硬件條件的不斷發(fā)展,很多大型數(shù)據(jù)庫(kù)的很多極其復(fù)雜的特性浅妆,今天看來(lái)逐漸成為了不必要望迎。今天的軟件用戶更加渴求“簡(jiǎn)單、實(shí)用凌外、綠色”辩尊。InterBase/FireBird數(shù)據(jù)庫(kù)幾乎就是為這個(gè)宗旨而量身定制的。

和InterBase/FireBird相當(dāng)?shù)臄?shù)據(jù)庫(kù)引擎還有MySQL康辑、PostGre SQL兩種數(shù)據(jù)庫(kù)摄欲。和后兩種數(shù)據(jù)庫(kù)相比,InterBase/FireBird數(shù)據(jù)庫(kù)有著最為充沛而友好的開(kāi)發(fā)工具疮薇,市面上專門用于這兩種數(shù)據(jù)庫(kù)的建庫(kù)工具胸墙,就不下十來(lái)種,幾乎每個(gè)資深的Delphi/IB/FB開(kāi)發(fā)者都恨不得自己也做一個(gè)管理工具按咒。最為流行的管理開(kāi)發(fā)工具迟隅,例如IBExpert,在不斷的發(fā)展完善下励七,其功能甚至于早已超過(guò)了其他商用大型數(shù)據(jù)庫(kù)的企業(yè)管理器智袭。InterBase/FireBird和Delphi、C++Builder兩種工具結(jié)合非常緊密掠抬,因而吼野,在C/S應(yīng)用開(kāi)發(fā)方面,InterBase/FireBird占有上風(fēng)两波,能夠開(kāi)發(fā)出最為細(xì)膩友好的客戶端UI瞳步。InterBase/FireBird數(shù)據(jù)庫(kù)目前正在迅速發(fā)展,它們所需要的是更多實(shí)戰(zhàn)應(yīng)用的考驗(yàn)腰奋,其中特別包括了大型Web應(yīng)用的考驗(yàn)单起。在這方面,MySQL相對(duì)而言更成熟一些氛堕。但是馏臭,隨著InterBase/FireBird用戶的不斷增多,筆者相信讼稚,這個(gè)只是個(gè)時(shí)間的問(wèn)題括儒。中型數(shù)據(jù)庫(kù)中,沒(méi)有一種數(shù)據(jù)庫(kù)提供了InterBase/FireBird所帶來(lái)的如此完備的內(nèi)在構(gòu)架锐想,如此豐富強(qiáng)大的SQL支持帮寻,如此簡(jiǎn)潔的使用、維護(hù)方式赠摇,以及精華所在的存儲(chǔ)過(guò)程語(yǔ)言固逗。相信這些優(yōu)異的特性總有一天會(huì)在業(yè)界放出應(yīng)有的光芒。

InterBase/FireBird數(shù)據(jù)庫(kù)是兩個(gè)分支的合稱藕帜。InterBase是Borland/CodeGear公司的數(shù)據(jù)庫(kù)產(chǎn)品烫罩,而FireBird則是開(kāi)源組織持續(xù)開(kāi)發(fā)的免費(fèi)開(kāi)源版本的InterBase。由于這兩種數(shù)據(jù)庫(kù)的核心特性幾乎完全一樣洽故,所以贝攒,筆者書中闡述的特性絕大多數(shù)都同時(shí)適用于兩種數(shù)據(jù)庫(kù)。讀者可以根據(jù)自己的情況需要时甚,在這兩種數(shù)據(jù)庫(kù)之間進(jìn)行選擇隘弊。在InterBase/FireBird支持者的持續(xù)推動(dòng)下CodeGear和FireBird開(kāi)發(fā)組織都在持續(xù)的改進(jìn)著這兩種數(shù)據(jù)庫(kù),所以荒适,在未來(lái)還會(huì)出現(xiàn)更多的新特性梨熙,這些也許會(huì)在本書的后續(xù)版本中涵蓋。相信本書的讀者刀诬,也許會(huì)經(jīng)常訪問(wèn)這兩種數(shù)據(jù)庫(kù)的官方網(wǎng)站咽扇,關(guān)注它們的發(fā)展,甚至于一定程度的參與到數(shù)據(jù)庫(kù)引擎的改進(jìn)中陕壹。

目前市面上關(guān)于InterBase/FireBird數(shù)據(jù)庫(kù)的書籍很早就已經(jīng)有了质欲,但是這些書籍都是關(guān)于這種數(shù)據(jù)庫(kù)本身的功能闡述,相當(dāng)于數(shù)據(jù)庫(kù)的中文手冊(cè)帐要,這些書籍對(duì)該數(shù)據(jù)庫(kù)的應(yīng)用開(kāi)發(fā)卻論述甚少把敞。本書的重點(diǎn)則在于針對(duì)這種數(shù)據(jù)庫(kù)的應(yīng)用開(kāi)發(fā)上,面向的是實(shí)戰(zhàn)性榨惠,包括和開(kāi)發(fā)工具的結(jié)合以及系統(tǒng)的構(gòu)架奋早,一些應(yīng)用開(kāi)發(fā)層面的高級(jí)技術(shù)將被展開(kāi)論述,這部分也是本書的精華所在赠橙,因而耽装,本書的讀者應(yīng)該是具備一定編程經(jīng)驗(yàn)的開(kāi)發(fā)者。好期揪,我在這里感謝各方面人士的支持掉奄,我們這就開(kāi)啟InterBase/FireBird數(shù)據(jù)庫(kù)激情之旅,執(zhí)行一句:

select ‘我們開(kāi)始使用InterBase/FireBird數(shù)據(jù)庫(kù)了!’?

as result from RDB$DATABASE

構(gòu)建高度智能化的關(guān)系數(shù)據(jù)庫(kù)系統(tǒng)

現(xiàn)代的應(yīng)用軟件系統(tǒng)的用戶姓建,越來(lái)越希望軟件系統(tǒng)更加的易于維護(hù)诞仓,使用過(guò)程透明化,希望軟件本身對(duì)人的要求更低速兔,盡量少的涉及專業(yè)的計(jì)算機(jī)知識(shí)墅拭,使計(jì)算機(jī)操作者能夠更加專注于業(yè)務(wù)本身。這些涣狗,或許就是所說(shuō)的“軟件系統(tǒng)智能化”谍婉。感謝InterBase/FireBird,使這一高度挑戰(zhàn)性的目標(biāo)實(shí)現(xiàn)起來(lái)并不困難镀钓。由于特定的歷史背景穗熬,InterBase/FireBird的開(kāi)發(fā)接口比其他數(shù)據(jù)庫(kù)公開(kāi)的更加徹底,再加之InterBase/FireBird數(shù)據(jù)庫(kù)的體系結(jié)構(gòu)也非常的簡(jiǎn)潔透明丁溅,所以用InterBase/FireBird構(gòu)架智能化的系統(tǒng)就來(lái)的比較順利唤蔗。

構(gòu)架純綠色客戶端軟件

所謂的“綠色軟件”,就是指唧瘾,程序文件拷貝到空白電腦上面措译,就能直接運(yùn)行,不必注冊(cè)ocx文件饰序、不必讀寫注冊(cè)表领虹、不必在系統(tǒng)文件夾下面拷貝文件、以及不必做其他特殊的操作求豫。隨著軟件風(fēng)格潮流的返璞歸真的趨勢(shì)塌衰,市面上很多的軟件產(chǎn)品都以標(biāo)榜自己為“綠色軟件”為榮◎鸺危“綠色軟件”的標(biāo)準(zhǔn)是有一定道理的最疆,一方面,它不會(huì)給操作系統(tǒng)環(huán)境帶來(lái)污染蚤告,另一方面努酸,更重要的一點(diǎn),綠色軟件有更好的健壯性和便攜性杜恰。例如获诈,如果系統(tǒng)需要在系統(tǒng)文件夾下面放置若干動(dòng)態(tài)庫(kù),那么這些動(dòng)態(tài)庫(kù)就有可能和其他系統(tǒng)的同名動(dòng)態(tài)庫(kù)產(chǎn)生沖突心褐,或產(chǎn)生不同版本的混淆舔涎,因而增加了故障的概率。Client/Server數(shù)據(jù)庫(kù)的綠色化并不是一件容易的事情逗爹,因?yàn)楹芏嗟拇笮蛿?shù)據(jù)庫(kù)的客戶端的安裝必須依賴數(shù)據(jù)庫(kù)開(kāi)發(fā)商提供的安裝程序亡嫌,完全的不透明。因此,開(kāi)發(fā)出小巧挟冠、綠色的客戶端軟件一直是商業(yè)開(kāi)發(fā)者的一個(gè)話題

值得一提的是于购,在開(kāi)發(fā)語(yǔ)言方面,目前最適合制作綠色軟件的圃郊,仍然是老牌子的Delphi/C++Builder for Win32价涝。我們這里以經(jīng)典的Delphi 7為例來(lái)考察綠色數(shù)據(jù)庫(kù)軟件的制作女蜈。有如往常一樣持舆,我們?cè)贒elphi中創(chuàng)建好一個(gè)應(yīng)用程序,養(yǎng)成良好的習(xí)慣就是伪窖,空白程序一上來(lái)逸寓,先創(chuàng)建后目錄結(jié)構(gòu),把可執(zhí)行文件輸出路徑和源代碼路徑分離開(kāi)來(lái)覆山,同時(shí)創(chuàng)建好數(shù)據(jù)庫(kù)存放路徑竹伸,路徑之間的相對(duì)關(guān)系盡量和用戶現(xiàn)場(chǎng)一致。如下圖簇宽,可執(zhí)行文件輸出路徑是Bin目錄勋篓,而數(shù)據(jù)庫(kù)文件存放在DB目錄下。

作為最簡(jiǎn)單的程序魏割,我們直接在主窗體上放置了數(shù)據(jù)庫(kù)連接控件譬嚣,并且在數(shù)據(jù)庫(kù)中創(chuàng)建了表,使控件在設(shè)計(jì)時(shí)連向了該數(shù)據(jù)庫(kù)钞它,幾乎與以前沒(méi)有什么差別:

編譯之后拜银,我們發(fā)現(xiàn)Bin目錄中多了一個(gè)999k的可執(zhí)行文件,執(zhí)行起來(lái)遭垛,和往常一樣順利:

運(yùn)行這個(gè)程序尼桶,我們用一個(gè)動(dòng)態(tài)庫(kù)分析工具看看它調(diào)用了哪些動(dòng)態(tài)庫(kù):

在筆者的Windows XP中,Delphi7是經(jīng)過(guò)一定改造的綠色版Delphi7锯仪,因此筆者的Windows的System32中可以說(shuō)只有WinXP自己原先的動(dòng)態(tài)庫(kù)泵督。從圖中可以看到,這個(gè)Project1.exe所用到的動(dòng)態(tài)庫(kù)庶喜,除了Windows的系統(tǒng)動(dòng)態(tài)庫(kù)之外小腊,只有g(shù)ds32.dll和midas.dll兩個(gè)dll。由此看來(lái)溃卡,Win32的Delphi開(kāi)發(fā)出的程序相當(dāng)?shù)母蓛艟G色溢豆。在InterBase/FireBird數(shù)據(jù)庫(kù)中,其客戶端就是一個(gè)小小的動(dòng)態(tài)庫(kù)(gds32.dll或者FBClient.dll)瘸羡,這樣漩仙,只要把客戶端動(dòng)態(tài)庫(kù)和應(yīng)用程序文件放到一起即可完成部署。好的,我們把動(dòng)態(tài)庫(kù)兩個(gè)動(dòng)態(tài)庫(kù)拷貝到Bin目錄下队他,這樣不就可以了卷仑?

確實(shí),如果按照最低的綠色軟件標(biāo)準(zhǔn)來(lái)衡量麸折,這樣確實(shí)已經(jīng)可以了锡凝,至少你的軟件拷貝到空白環(huán)境中,真的可以運(yùn)行起來(lái)垢啼。然而窜锯,作為專業(yè)級(jí)別的軟件開(kāi)發(fā)者,我們要快速的制作膾炙人口的軟件作品芭析,那么在知識(shí)上的要求就不能僅于此了锚扎。我們要結(jié)合Delphi和InterBase/FireBird數(shù)據(jù)庫(kù)的特點(diǎn),總結(jié)一套專門開(kāi)發(fā)綠色軟件系統(tǒng)的思路來(lái)馁启。幸虧Delphi是開(kāi)發(fā)綠色軟件的能手驾孔,這使思路總結(jié)出來(lái)后,相當(dāng)?shù)那逦?/p>

如果用更加嚴(yán)格的眼光來(lái)看惯疙,這個(gè)小小的范例程序立即就需要一個(gè)重要的改進(jìn)翠勉,那就是在單元的Uses中加入一個(gè)單元:MidasLib。好霉颠,筆者做了這件事情对碌,從新編譯,看看目標(biāo)文件掉分,發(fā)現(xiàn)竟然多了200K俭缓。這究竟發(fā)生了什么?這是因?yàn)镸idasLib是Midas.dll的靜態(tài)庫(kù)酥郭。把它囊括到可執(zhí)行文件之中华坦,可執(zhí)行文件就不必再部署Midas.dll動(dòng)態(tài)庫(kù)了。從新分析一下這個(gè)可執(zhí)行文件的動(dòng)態(tài)庫(kù)調(diào)用不从,發(fā)現(xiàn)果然沒(méi)有了Midas.dll惜姐。Midas.dll對(duì)于Delphi程序來(lái)說(shuō),是一個(gè)特殊的動(dòng)態(tài)庫(kù)椿息,它本身是一個(gè)COM庫(kù)歹袁,需要注冊(cè)。系統(tǒng)在尋找這樣的動(dòng)態(tài)庫(kù)時(shí)寝优,并非完全遵循Path路徑条舔,而是先看看注冊(cè)表記錄的路徑,如果不存在乏矾,則會(huì)自動(dòng)注冊(cè)Path內(nèi)能夠找到的Midas.dll孟抗。然而迁杨,Delphi的每個(gè)不同的版本,都會(huì)帶有不同版本的Midas.dll凄硼,這樣铅协,機(jī)器上所有程序,都引用最后一次安裝的Midas.dll摊沉,這樣狐史,必然造成混亂。所以说墨,在單元的Uses中加入MidasLib是非常必要的舉動(dòng)骏全,直接讓程序免去依賴MidasLib⊥竦叮可執(zhí)行文件+gds32.dll才是比較到位的綠色軟件吟温。對(duì)于一個(gè)有經(jīng)驗(yàn)的軟件設(shè)計(jì)人員而言,他的頭腦中應(yīng)該很清醒設(shè)計(jì)中存在哪些影響軟件綠色化的因素突颊,以及有一套評(píng)測(cè)軟件綠色程度的標(biāo)準(zhǔn)和流程。筆者在這里試圖做一個(gè)詳盡的總結(jié):

1潘悼、? 總結(jié)系統(tǒng)所用到的VCL控件集列表律秃,列出每個(gè)控件的外部依賴性。一般來(lái)說(shuō)治唤,通常所說(shuō)的“純VCL”控件都是徹底綠色的組件棒动,也就是說(shuō)不必附帶任何文件。但是也有很多VCL控件包需要外帶動(dòng)態(tài)庫(kù)宾添、ocx船惨、甚至驅(qū)動(dòng)程序。這些都應(yīng)該在列表中體現(xiàn)缕陕。

2粱锐、? 除了VCL對(duì)象之外,系統(tǒng)是否用到了DLL或COM庫(kù)扛邑?這需要對(duì)程序本身所用到的東西做一個(gè)統(tǒng)計(jì)怜浅。若系統(tǒng)需要部署帶有ocx后綴的文件,很明顯蔬崩,系統(tǒng)中用了ActiveX恶座。但是,很多的COM對(duì)象庫(kù)可能是以其他的后綴結(jié)尾沥阳,例如跨琳,dll。這需要開(kāi)發(fā)者自己分析和整理桐罕。

3脉让、? 明確程序中用到了哪幾種數(shù)據(jù)庫(kù)樟氢,以及針對(duì)每種數(shù)據(jù)庫(kù)的訪問(wèn)方式。不同的訪問(wèn)方式有著不同的外部依賴性侠鳄。如下表:

數(shù)據(jù)庫(kù)引擎綠色程度

通用引擎BDE/SQL Links紅色

通用引擎DBX綠色埠啃,但需要部署動(dòng)態(tài)庫(kù)

InterBase/FireBirdIBX純綠色

FIBPlus純綠色

通用引擎ADO對(duì)于MS數(shù)據(jù)庫(kù)平臺(tái):綠色,但依賴OS的MDAC的版本

對(duì)于其他數(shù)據(jù)庫(kù)平臺(tái)需要部署OLE DB Provider

文件數(shù)據(jù)庫(kù)EasyTable純綠色

AbsoluteDB純綠色

Halcyon純綠色

內(nèi)存表dxMemData純綠色

KbmMemTable純綠色

ClientDataSet純綠色(需要引用MidasLib)

OracleODAC純綠色

4伟恶、? 明確所訪問(wèn)的數(shù)據(jù)庫(kù)的客戶端部署需要哪些文件碴开。最容易處理的,就是客戶端只要稍許動(dòng)態(tài)庫(kù)即可的數(shù)據(jù)庫(kù)平臺(tái)博秫,這樣的環(huán)境可以算成綠色客戶端環(huán)境潦牛。但很多著名的數(shù)據(jù)庫(kù)并不是如此,很可能需要注冊(cè)COM對(duì)象挡育,甚至于必需運(yùn)行數(shù)據(jù)庫(kù)廠商提供的安裝盤巴碗。

5、? 軟件進(jìn)入測(cè)試環(huán)節(jié)后即寒,應(yīng)該用動(dòng)態(tài)庫(kù)依賴測(cè)試工具來(lái)分析程序在運(yùn)行期間加載了哪些動(dòng)態(tài)庫(kù)橡淆。這一點(diǎn)仍然是非常重要的。這是對(duì)程序運(yùn)行時(shí)依賴性的一種驗(yàn)證母赵。如果程序“一不小心”調(diào)用了某些“不干凈”的代碼逸爵,那么在這個(gè)測(cè)試環(huán)節(jié)中即可直接體現(xiàn)出來(lái)。如果沒(méi)有測(cè)試工具凹嘲,則也可以直接在開(kāi)發(fā)工具的調(diào)試狀態(tài)下师倔,查看程序進(jìn)程的Modules列表。

6周蹭、? 軟件在測(cè)試的后期趋艘,可以直接在干凈的OS上試運(yùn)轉(zhuǎn)。目前諸如VMWare之類的虛擬軟件非常成熟了凶朗,可以借助這種工具來(lái)方便軟件的測(cè)試瓷胧。

在InterBase/FireBird這個(gè)專題開(kāi)發(fā)領(lǐng)域,“綠色”的概念還有著更加深入的內(nèi)涵俱尼,我們下面進(jìn)行深入一些的討論抖单。

1、? 如果我們的系統(tǒng)是面向單機(jī)用戶遇八,那么我們不妨考慮一下Embeded FireBird矛绘。這是把整個(gè)FireBird數(shù)據(jù)庫(kù)合并到客戶端動(dòng)態(tài)庫(kù)中的一個(gè)版本。也就是說(shuō)刃永,整個(gè)Server的功能都已經(jīng)包含在了gds32.dll或者fbclient.dll中货矮,那么程序的運(yùn)行也就不再依賴于必需安裝FireBird Server或者InterBase Server。這樣一來(lái)斯够,一個(gè)可執(zhí)行文件加上幾個(gè)動(dòng)態(tài)庫(kù)囚玫,干凈利索的構(gòu)成了一個(gè)復(fù)雜的單機(jī)數(shù)據(jù)庫(kù)系統(tǒng)喧锦,直接就能運(yùn)轉(zhuǎn)起來(lái),這是所有單機(jī)數(shù)據(jù)庫(kù)系統(tǒng)都希望達(dá)到的效果抓督。它完全免去了數(shù)據(jù)庫(kù)引擎的安裝燃少,真正實(shí)現(xiàn)了“便攜”的效果。

2铃在、? 把數(shù)據(jù)庫(kù)服務(wù)器的安裝包含到我們自己的程序中阵具。這個(gè)特性是FireBird數(shù)據(jù)庫(kù)所獨(dú)有的。FireBird的部署完全免費(fèi)定铜,并且提供了相應(yīng)的服務(wù)安裝的支持文件阳液,這使得數(shù)據(jù)庫(kù)的安裝可以完全合并到程序本身之中,使數(shù)據(jù)庫(kù)服務(wù)成為系統(tǒng)的一部分揣炕×泵螅可喜的是,F(xiàn)ireBird Server引擎本身也是純綠色的畸陡,這使得全自動(dòng)安裝服務(wù)器變得非常輕松鹰溜,只要運(yùn)行以下命令即可:

instreg install –z

instsvc install -auto -superserver -guardian –z

instsvc start

3、? gds32.dll可以編譯到可執(zhí)行文件的資源之中罩锐,運(yùn)行時(shí)奉狈,可以從資源中調(diào)用該動(dòng)態(tài)庫(kù)。對(duì)于IBX而言涩惑,這恐怕需要修改IBIntf.pas單元,以及使用第三方的動(dòng)態(tài)庫(kù)資源加載代碼來(lái)達(dá)到這個(gè)效果桑驱。這些筆者已經(jīng)為大家做好了竭恬,相關(guān)文件可以在本書的附帶光盤中找到。這個(gè)技術(shù)給人的第一印象就是比較“酷”熬的,它能夠真正的做到痊硕,讓客戶端程序是一個(gè)完全獨(dú)立的可執(zhí)行文件,客戶端除了這個(gè)可執(zhí)行文件以外押框,不必部署任何其他文件岔绸,包括數(shù)據(jù)庫(kù)的客戶端。不過(guò)橡伞,在實(shí)際應(yīng)用中盒揉,我們發(fā)現(xiàn)很多情況下這未必是一個(gè)最好的做法,因?yàn)镕ireBird/InterBase是一個(gè)快速發(fā)展的數(shù)據(jù)庫(kù)平臺(tái)兑徘,如果把客戶端動(dòng)態(tài)庫(kù)合并入可執(zhí)行文件刚盈,那么要升級(jí)新版本的引擎出現(xiàn)的時(shí)候,恐怕就必需得從新編譯程序了挂脑。特別是FireBird藕漱,幾乎每年都會(huì)有數(shù)個(gè)新的引擎版本欲侮,那么對(duì)于一些追求完美的人來(lái)說(shuō),不停的編譯程序?qū)⑹且患纯嗟氖虑槔吡5菍?duì)于某些場(chǎng)合而言威蕉,這個(gè)技巧仍是一個(gè)非常有用的東西,例如橄仍,我們想把數(shù)據(jù)庫(kù)的客戶端編寫在一個(gè)ActiveForm中韧涨,這樣就省去了附帶dll的麻煩。

FireBird/InterBase數(shù)據(jù)庫(kù)引擎本身就傾向于綠色和免維護(hù)沙兰,那么我們?cè)陂_(kāi)發(fā)系統(tǒng)的時(shí)候氓奈,不妨就朝著這個(gè)方向努力,使我們的系統(tǒng)也變得綠色起來(lái)鼎天。除了數(shù)據(jù)庫(kù)方面的東西以外舀奶,第三方控件的選擇也是另一方向射众。一般而言吗垮,選擇控件一定要盡量選擇“純VCL”芭届,它不僅代表著綠色拄丰,也往往代表著最好的性能和效率廉涕。幾乎所有的ActiveX扬蕊,都能找到相應(yīng)的VCL替代品斤讥。例如退个,微軟的串口訪問(wèn)控件MS COMM桑包,可以用免費(fèi)開(kāi)源的CPort代替南蓬。筆者曾經(jīng)開(kāi)發(fā)的基于FireBird的考勤系統(tǒng)就是采用了Cport。

數(shù)據(jù)庫(kù)管理維護(hù)功能(Administration)模塊的開(kāi)發(fā)

對(duì)于FireBird/InterBase數(shù)據(jù)庫(kù)系統(tǒng)而言哑了,數(shù)據(jù)庫(kù)的維護(hù)工作是一個(gè)非常重要的內(nèi)容赘方。它包含了以下幾部分:

1、? 數(shù)據(jù)庫(kù)帳號(hào)的維護(hù)

2弱左、? 數(shù)據(jù)庫(kù)文件的拷貝窄陡、復(fù)制

3、? 數(shù)據(jù)庫(kù)的備份拆火、壓縮

4跳夭、? 數(shù)據(jù)庫(kù)的檢查診斷

5、? 創(chuàng)建鏡像

6们镜、? 設(shè)定數(shù)據(jù)庫(kù)的運(yùn)行模式币叹、屬性參數(shù)

對(duì)于很多數(shù)據(jù)庫(kù)而言,上述任務(wù)的完成往往需要數(shù)據(jù)庫(kù)管理員在數(shù)據(jù)庫(kù)的管理控制臺(tái)工具中完成憎账,甚至于需要在命令行狀態(tài)下敲入特定的命令套硼。對(duì)于智能化的系統(tǒng)來(lái)說(shuō),這些胞皱,都應(yīng)該通過(guò)程序的圖形化界面來(lái)體現(xiàn)邪意。要達(dá)到這個(gè)效果九妈,需要我們的程序本身就包含數(shù)據(jù)庫(kù)管理模塊。FireBird/InterBase提供了開(kāi)放的Administration開(kāi)發(fā)接口雾鬼,使得這一切變得很輕松萌朱。

數(shù)據(jù)庫(kù)帳號(hào)的維護(hù)

我們要更改數(shù)據(jù)庫(kù)的帳號(hào),需要使用IBX的IBSecurityService控件策菜。它的使用方法如下:

IBSecurityService1.Params.Values['user_name'] := ‘sysdba’;

IBSecurityService1.Params.Values['password']? := ‘masterkey’;//寫入管理員密碼

IBSecurityService1.ServerName := 'LocalHost';//寫入服務(wù)器名稱

IBSecurityService1.Active := True;

IBSecurityService1.UserName := ‘ANewName’;//寫入被更改或添加的用戶名稱

IBSecurityService1.Password := ‘NewPass’;//寫入新的密碼

IBSecurityService1.ModifyUser;//更改已有帳號(hào)

//IBSecurityService1.AddUser ;//添加新的帳號(hào)

//IBSecurityService1.DeleteUser ;//刪除帳號(hào)

我們可以看到用IBSecurityService控件來(lái)增晶疼、刪、改數(shù)據(jù)庫(kù)帳號(hào)非常的方便簡(jiǎn)捷又憨。上述的代碼可以作為一個(gè)函數(shù)提供在程序的主服務(wù)模塊中翠霍。但是需要指出的是,一個(gè)用戶創(chuàng)建好了之后蠢莺,并不意味著可以直接以該用戶登錄來(lái)使用數(shù)據(jù)庫(kù)中的所有對(duì)象寒匙。相反,此時(shí)的新用戶躏将,恐怕無(wú)法使用數(shù)據(jù)庫(kù)中的任何對(duì)象锄弱。這是因?yàn)椋聞?chuàng)建的用戶祸憋,必需通過(guò)Grant命令來(lái)賦予相應(yīng)的權(quán)限会宪。所以,如果系統(tǒng)是動(dòng)態(tài)創(chuàng)建用戶蚯窥,則往往在上述代碼執(zhí)行后掸鹅,用IBScript控件來(lái)執(zhí)行一系列的Grant命令。在很多時(shí)候拦赠,我們構(gòu)建系統(tǒng)并不用如此緊密的依賴數(shù)據(jù)庫(kù)平臺(tái)本身的權(quán)限機(jī)制河劝,畢竟這樣的做法在開(kāi)發(fā)上非常繁瑣。我們更加常用的做法則是在固定的系統(tǒng)管理員帳號(hào)的基礎(chǔ)上矛紫,我們自己構(gòu)架一套帳號(hào)機(jī)制,把我們的操作員保存在我們的一張表中牌里,通過(guò)我們自己的代碼來(lái)進(jìn)行權(quán)限認(rèn)證颊咬。這種情況,我們僅需要使用IBSecurityService1.ModifyUser來(lái)改變sysdba的密碼就夠用了牡辽。sysdba密碼連同服務(wù)器連接串在客戶端程序中被加密的保存在一個(gè)本地的文件中喳篇,這樣每次登錄的時(shí)候,用戶只需要輸入操作員的帳號(hào)态辛,即可登錄麸澜。在某些特定的場(chǎng)合,程序可能需要多種不同角色的帳號(hào)內(nèi)部使用奏黑,這種情況炊邦,便可以充分的運(yùn)用IBSecurityService空間和grant命令來(lái)實(shí)現(xiàn)相應(yīng)的功能模塊编矾。在簡(jiǎn)單的關(guān)系數(shù)據(jù)庫(kù)系統(tǒng)中,系統(tǒng)管理員的密碼修改功能馁害,可以直接合并到登錄框窗體中窄俏,這對(duì)于很多場(chǎng)合,不失為是一種既方便用戶碘菜,又方便開(kāi)發(fā)者的一種做法:

數(shù)據(jù)庫(kù)文件的拷貝凹蜈、復(fù)制

InterBase/FireBird數(shù)據(jù)庫(kù)有著和Access一樣的一個(gè)特點(diǎn),那就是數(shù)據(jù)庫(kù)是一個(gè)單獨(dú)的文件忍啸。這一點(diǎn)非常有利于制作高度智能化的數(shù)據(jù)庫(kù)系統(tǒng)仰坦。因?yàn)閷?duì)某個(gè)數(shù)據(jù)庫(kù)的拷貝,簡(jiǎn)單到了只需要拷貝一個(gè)文件的地步计雌。盡管直接復(fù)制數(shù)據(jù)庫(kù)文件比Gbak工具生成的gbk文件來(lái)說(shuō)體積要大一些悄晃,但是它是一種最為直接的備份方式。對(duì)于硬盤空間充沛的系統(tǒng)白粉,這種方式來(lái)實(shí)現(xiàn)自動(dòng)備份最為靈活簡(jiǎn)單传泊。拷貝硬盤文件的方法鸭巴,可以是調(diào)用API函數(shù)(例如CopyFile)眷细,也可以直接調(diào)用Shell命令。由于Shell命令有著更好的靈活性和更豐富的功能鹃祖,所以是一種更加常用的自動(dòng)維護(hù)功能的實(shí)現(xiàn)方法溪椎。我們先給出一個(gè)函數(shù):

procedure DoCMD(CMD: string);?

var?

Buf: array[0..511] of char;?

AFileName: string;?

begin?

GetSystemDirectory(Buf, SizeOf(Buf));?

AFileName := Buf;?

AFileName := AFileName + '\CMD.exe';?

ShellExecute(0, '', PChar(AFileName), PChar('/C ' + CMD), '',?SW_HIDE);?

end;

在這個(gè)函數(shù)的幫助下,我們可以執(zhí)行任意的DOS命令恬口,包括拷貝文件:

DoCMD('copy c:\test\db1.gdb d:\bak\' + DateToStr(Now) + '.gdb');

如果我們希望做更加復(fù)雜一些的操作校读,比如,將數(shù)據(jù)庫(kù)文件拷貝到特定目錄下壓縮祖能,或者啟動(dòng)歉秫、終止某些服務(wù)程序,我們可以根據(jù)特定的命令格式編寫批處理文件养铸,然后用DoCMD函數(shù)來(lái)執(zhí)行該批處理雁芙。本書列出3個(gè)非常有用的命令:

a)???????? iisreset /stop和iisreset /start:這是啟動(dòng)或停止IIS服務(wù)的命令。如果讀者的系統(tǒng)參與了IIS中的Web功能钞螟,那么就有可能需要讓IIS服務(wù)停止或啟動(dòng)兔甘。

b)??????? sc stop和sc start:?jiǎn)?dòng)或停止某服務(wù)程序的命令,需要添加一個(gè)參數(shù)鳞滨。例如洞焙,對(duì)于停止FireBird服務(wù)來(lái)說(shuō),是sc stop FirebirdServerDefaultInstance。如果我們需要一個(gè)服務(wù)名稱的列表澡匪,那么我們可以在命令行中執(zhí)行以下命令:

sc query type= service>C:\log.txt

這樣在C:\就會(huì)產(chǎn)生一個(gè)log.txt文件熔任,里面列舉著每個(gè)命令的名稱和狀態(tài)。

c)??????? 壓縮命令仙蛉。目前WinRAR是最為流行的壓縮工具笋敞,很多開(kāi)發(fā)者希望用這種方式來(lái)自動(dòng)備份數(shù)據(jù)庫(kù)文件,那么相應(yīng)的命令范例如下:

”C:\Program Files\WinRAR\RAR.exe”? a? DB.rar? “c:\test\db1.gdb”

不過(guò)荠瘪,WinRAR工具包畢竟不是免費(fèi)的夯巷,這使得系統(tǒng)對(duì)這個(gè)工具的依賴比較不利。我們可以推薦更加緊縮的第三方免費(fèi)開(kāi)源的7Zip工具哀墓,其官方網(wǎng)址為:?

http://www.7-zip.org/zh-cn/?

上述命令對(duì)于7zip而言趁餐,它和WinRAR的幾乎完全一樣:

” C:\Program Files\7-Zip\7z.exe”? a? DB.rar? “c:\test\db1.gdb”

7Zip無(wú)與倫比的壓縮比率,全開(kāi)放的接口篮绰,使它能更好的勝任數(shù)據(jù)庫(kù)壓縮備份的任務(wù)后雷,因而能夠很好的被數(shù)據(jù)庫(kù)備份工具運(yùn)用。(當(dāng)然吠各,還可以避開(kāi)Shell的方式臀突,在程序中直接使用7Zip的開(kāi)發(fā)包來(lái)做壓縮模塊,但這種方式和7Zip結(jié)合太緊密贾漏,缺乏靈活性)

通過(guò)上述的方法候学,我們能夠非常方便的實(shí)現(xiàn)各種文件復(fù)制、移動(dòng)纵散、刪除等功能梳码,實(shí)現(xiàn)數(shù)據(jù)庫(kù)文件的備份。

在InterBase/FireBird為基礎(chǔ)的系統(tǒng)中伍掀,數(shù)據(jù)庫(kù)復(fù)制模塊往往會(huì)是下面的形態(tài)

1掰茶、? 在數(shù)據(jù)庫(kù)所在的計(jì)算機(jī)上,開(kāi)啟一個(gè)服務(wù)程序蜜笤,該程序按照特定的時(shí)間頻率濒蒋,將數(shù)據(jù)庫(kù)文件作復(fù)制。這就是定期自動(dòng)直接備份把兔。備份的文件啊胶,按照時(shí)間的次序,循環(huán)滾動(dòng)存放在特定命名規(guī)則的目錄下垛贤,過(guò)期的文件將被覆蓋。當(dāng)然做到按照時(shí)間周期來(lái)運(yùn)行某個(gè)功能趣倾,有兩種做法聘惦,第一就是在程序中通過(guò)Timer來(lái)實(shí)現(xiàn);第二種就是把功能做到程序中之后,通過(guò)Windows的計(jì)劃任務(wù)來(lái)按照特定周期來(lái)調(diào)用善绎。

2黔漂、? 在應(yīng)用服務(wù)器或WebServer上,包含一個(gè)數(shù)據(jù)庫(kù)復(fù)制模塊禀酱。用戶在客戶端可以根據(jù)自己的要求來(lái)讓系統(tǒng)做出復(fù)制動(dòng)作炬守。

3、? 在服務(wù)期端有一個(gè)圖形化的管理工具剂跟,打開(kāi)工具可以進(jìn)行庫(kù)文件的復(fù)制减途,甚至于管理工具帶有光盤刻錄的功能,能夠把文件直接刻錄到光盤上曹洽。

數(shù)據(jù)庫(kù)的備份鳍置、壓縮

FireBird/InterBase提供了專門的備份、恢復(fù)功能送淆。和上述直接備份數(shù)據(jù)庫(kù)文件不同的是税产,真正的數(shù)據(jù)庫(kù)的備份文件其實(shí)是一個(gè)“可便攜的”(Portable)緊縮的數(shù)據(jù)文件。FireBird/InterBase的這個(gè)功能和它們提供的gbak命令是相關(guān)的偷崩。在比較早期的時(shí)候辟拷,InterBase比較偏重于Unix操作系統(tǒng)平臺(tái),那時(shí)候備份InterBase數(shù)據(jù)庫(kù)都是用gbak命令:

備份: gbak.exe -USER "sysdba" -PAS "masterkey"? -B? DATA.GDB? DATA.fbk

恢復(fù): gbak.exe -USER "sysdba" -PAS "masterkey"? -REP? DATA.fbk? DATA.GDB

現(xiàn)在這一傳統(tǒng)功能仍然被保留阐斜。不過(guò)我們卻并不希望用戶到黑黑的命令行中敲入如此晦澀難記的命令衫冻,而是我們的程序代替用戶做了這件事情。我們讓我們的程序執(zhí)行上述shell命令智听,即可達(dá)到備份恢復(fù)的目地羽杰。FireBird/InterBase數(shù)據(jù)庫(kù)的備份恢復(fù)有著重要的意義。這是因?yàn)镕ireBird/InterBase數(shù)據(jù)庫(kù)運(yùn)行一段時(shí)間之后到推,數(shù)據(jù)庫(kù)中會(huì)殘留大量的垃圾頁(yè)面考赛,數(shù)據(jù)頁(yè)的排列也不連貫,這樣莉测,不僅數(shù)據(jù)庫(kù)的體積膨脹颜骤,而且數(shù)據(jù)庫(kù)的性能也受到很大的影響。當(dāng)我們使用gbak把數(shù)據(jù)庫(kù)做出備份捣卤,然后由該備份文件恢復(fù)出一個(gè)全新的數(shù)據(jù)庫(kù)后忍抽,這個(gè)全新的數(shù)據(jù)庫(kù)就會(huì)從新變得很緊縮,性能會(huì)恢復(fù)如初董朝。所以智能化的關(guān)系數(shù)據(jù)庫(kù)系統(tǒng)應(yīng)該能做到定期的備份恢復(fù)數(shù)據(jù)庫(kù)鸠项。更高標(biāo)準(zhǔn)的對(duì)數(shù)據(jù)的備份的要求,是用gbak備份出數(shù)據(jù)之后子姜,然后用7zip來(lái)壓縮祟绊,這樣,備份的數(shù)據(jù)非常的緊縮,占據(jù)很小的存儲(chǔ)空間牧抽。數(shù)據(jù)庫(kù)的真?zhèn)浞輰?shí)現(xiàn)方式嘉熊,也和上述的shell命令實(shí)現(xiàn)文件的拷貝相類似,通過(guò)DoCMD來(lái)調(diào)用gbak命令扬舒,并通過(guò)其它的命令阐肤、批處理來(lái)實(shí)現(xiàn)服務(wù)的起停、文件的壓縮讲坎。這個(gè)功能可以做到數(shù)據(jù)庫(kù)服務(wù)器上的一個(gè)周期運(yùn)行的程序中孕惜,也可以做到應(yīng)用服務(wù)器上供客戶端的用戶手動(dòng)調(diào)用。上面提到的很多方法在這里都可以使用衣赶。不過(guò)诊赊,在Delphi的IBX控件中,還提供了兩個(gè)控件府瞄,支持用戶在客戶端進(jìn)行備份碧磅、恢復(fù):IBBackupService、IBRestoreService

以IBBackupService為例遵馆,典型范例代碼如下:

IBBackupService1.Params.Values['user_name'] := 'sysdba';

IBBackupService1.Params.Values['password'] := 'masterkey';

IBBackupService1.ServerName?? := 'LocalHost';

IBBackupService1.DatabaseName := IBDB.DatabaseName;

IBBackupService1.BackupFile.Clear;

IBBackupService1.BackupFile.Add('C:\test.gbk');

IBBackupService1.Attach;

IBBackupService1.ServiceStart;

IBBackupService1.Detach;

這兩個(gè)控件比較的簡(jiǎn)單易用鲸郊,使用代碼幾乎相同,不必贅述货邓。

數(shù)據(jù)庫(kù)的檢查診斷

對(duì)于專業(yè)級(jí)別的數(shù)據(jù)庫(kù)系統(tǒng)來(lái)說(shuō)秆撮,應(yīng)該在系統(tǒng)中提供特定的數(shù)據(jù)庫(kù)狀態(tài)診斷工具。在特定的情況下换况,數(shù)據(jù)庫(kù)的運(yùn)行中會(huì)在數(shù)據(jù)庫(kù)內(nèi)部引入數(shù)據(jù)的瑕疵頁(yè)面职辨。定期對(duì)數(shù)據(jù)庫(kù)進(jìn)行診斷,能夠及早的發(fā)現(xiàn)數(shù)據(jù)庫(kù)瑕疵戈二,盡早的采取有效的措施舒裤,消除瑕疵,避免數(shù)據(jù)庫(kù)的崩潰觉吭。在FireBird/InterBase數(shù)據(jù)庫(kù)中腾供,同樣提供了兩種開(kāi)發(fā)接口來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的診斷。第一鲜滩,就是gfix命令行工具伴鳖,第二就是ibx中提供的IBValidationService控件。

對(duì)于gfix來(lái)說(shuō)徙硅,我們可以像使用gbak那樣來(lái)通過(guò)命令行來(lái)調(diào)用榜聂。參數(shù)列表如下:

-activate?????? activate shadow file for database usage

-attach???????? shutdown new database attachments

-buffers??????? set page buffers

-commit???????? commit transaction

-cache????????? shutdown cache manager

-full?????????? validate record fragments (-v)

-force????????? force database shutdown

-housekeeping?? set sweep interval

-ignore???????? ignore checksum errors

-kill?????????? kill all unavailable shadow files

-list?????????? show limbo transactions

-mend?????????? prepare corrupt database for backup

-mode?????????? read_only or read_write

-no_update????? read-only validation (-v)

-online???????? database online

-prompt???????? prompt for commit/rollback (-l)

-password?????? default password

-rollback?????? rollback transaction

-sql_dialect??? set database dialect n

-sweep????????? force garbage collection

-shut?????????? shutdown

-two_phase????? perform automated two-phase recovery

-tran?????????? shutdown transaction startup

-use??????????? use full or reserve space for versions

-user?????????? default user name

-validate?????? validate database structure

-write????????? write synchronously or asynchronously

-z????????????? print software version number

典型的用法是:

gfix.exe -USER "sysdba" -PAS "masterkey" -force -validate MyServer:C:\test\DATA.GDB?

不過(guò),和gbak不同的是嗓蘑,gfix將返回一系列的信息峻汉,我們必須截獲這些信息來(lái)判斷數(shù)據(jù)庫(kù)是否存在問(wèn)題贴汪。如果用Shell的方式調(diào)用的話,就會(huì)涉及到從Shell中截獲控制臺(tái)程序的輸出流休吠,那么在開(kāi)發(fā)上有些麻煩(盡管完全可以實(shí)現(xiàn))。我們更推薦第二種方式业簿,那就是使用IBX的控件:IBValidationService

用法如下:

IBValidationService1.Params.Values['user_name'] := 'sysdba';?

IBValidationService1.Params.Values['password'] := 'masterkey';?

IBValidationService1.ServerName?? := 'LocalHost';?

IBValidationService1.DatabaseName := IBDB.DatabaseName;?

IBValidationService1.Attach;?

IBValidationService1.ServiceStart;?

while IBValidationService1.IsServiceRunning do?

Application.ProcessMessages;?

IBValidationService1.Detach;

在這個(gè)控件中瘤礁,藍(lán)色部分是它的最重要屬性。包括了檢查梅尤、修復(fù)柜思、

忽略壞的記錄等等多種功能。通過(guò)這個(gè)控件巷燥,我們能夠很好的對(duì)

數(shù)據(jù)庫(kù)進(jìn)行檢查赡盘、乃至修復(fù)。

創(chuàng)建鏡像

鏡像功能(Shadow)是InterBase /FireBird特有的特性缰揪,它是在數(shù)據(jù)庫(kù)運(yùn)行中陨享,由系統(tǒng)自動(dòng)維護(hù)的該數(shù)據(jù)庫(kù)的一模一樣的另一個(gè)或多個(gè)庫(kù)文件(也就是鏡像庫(kù),或稱之Shadow)钝腺。也就是說(shuō)抛姑,當(dāng)主數(shù)據(jù)庫(kù)發(fā)生任何數(shù)據(jù)更改動(dòng)作的時(shí)候,InterBase /FireBird Server將同時(shí)把發(fā)生的任何數(shù)據(jù)變化同步的更新到鏡像庫(kù)中艳狐。毫無(wú)疑問(wèn)定硝,這種機(jī)制的目地是為了獲取更大的可靠性、提高InterBase /FireBird數(shù)據(jù)庫(kù)的健壯性毫目。當(dāng)主數(shù)據(jù)庫(kù)產(chǎn)生瑕疵甚至于發(fā)生崩潰的時(shí)候蔬啡,其Shadow很有可能是一個(gè)完好的數(shù)據(jù)庫(kù),在這種災(zāi)難性的場(chǎng)景下镀虐,人們可以將鏡像庫(kù)恢復(fù)成為主數(shù)據(jù)庫(kù)箱蟆,進(jìn)而可以避免系統(tǒng)崩潰帶來(lái)的巨大損失。鏡像功能可以說(shuō)是一種類似于硬盤并聯(lián)陣列那樣的機(jī)制粉私,用數(shù)據(jù)的副本來(lái)?yè)Q取可靠性顽腾、堅(jiān)固性,只不過(guò)鏡像功能是通過(guò)軟件來(lái)實(shí)現(xiàn)的诺核。在一些惡劣的環(huán)境下抄肖,鏡像功能會(huì)顯得尤為重要。因?yàn)橛脩舻臉I(yè)務(wù)現(xiàn)場(chǎng)千差萬(wàn)別窖杀,可能有各種難以預(yù)料的情況漓摩,特別是InterBase /FireBird由于其便捷性,它們經(jīng)常被安裝在普通的個(gè)人電腦上充當(dāng)服務(wù)器入客,這樣的話管毙,電腦的掉電腿椎、病毒導(dǎo)致OS崩潰、打開(kāi)程序過(guò)多導(dǎo)致內(nèi)存用盡夭咬、硬盤質(zhì)量低下等等因素都會(huì)增加數(shù)據(jù)庫(kù)崩潰的概率啃炸。經(jīng)歷過(guò)客戶方的數(shù)據(jù)庫(kù)崩潰的開(kāi)發(fā)者對(duì)此必然印象深刻,特別是卓舵,用戶現(xiàn)場(chǎng)災(zāi)難發(fā)生后南用,我們這些系統(tǒng)的締造者們不得不親臨現(xiàn)場(chǎng),傷透腦筋用盡各種辦法去搶救那些致命的業(yè)務(wù)數(shù)據(jù)掏湾,當(dāng)嘗試了各種渠道也無(wú)法挽回這些數(shù)據(jù)時(shí)裹虫,我們真的有“上天無(wú)路、入地?zé)o門”的感覺(jué)融击。目前市面上的所有的數(shù)據(jù)庫(kù)有發(fā)生崩潰的案例筑公,包括最著名的Oracle、MS SQL等等尊浪,當(dāng)然匣屡,我們的InterBase /FireBird也有這種事例。因?yàn)楫a(chǎn)生數(shù)據(jù)崩潰的硬盤瑕疵往往是非常偶然發(fā)生的际长,因此當(dāng)存在一個(gè)或多個(gè)鏡像庫(kù)的時(shí)候耸采,在災(zāi)難的情況下,我們幾乎總能從鏡像庫(kù)中找到狀態(tài)好得多的工育、或者是毫無(wú)問(wèn)題的數(shù)據(jù)庫(kù)副本虾宇,正是這些,讓現(xiàn)場(chǎng)的我們長(zhǎng)吁一口氣如绸。由此我們能夠感受到Shadow功能對(duì)于InterBase /FireBird而言是多么的重要嘱朽。

講了很多的理論,回頭看InterBase /FireBird的鏡像的使用怔接,卻十分的簡(jiǎn)單搪泳,它是通過(guò)執(zhí)行下面的SQL命令來(lái)進(jìn)行的:

Create Shadow Set_Num [Auto|Manul] [Conditional] ‘Filespec’ [Length [=] Int [Page[S]]] [Secondary_File];

其中:

<Secondary_File>= File ‘Filespec’ [<Fileinfo>] [Seconary_File] <Fileinfo>={Length[=]Int [Page[S]]| Starting [At [Page]] Int} [ <Fileinfo>]

Set_Num是影像集合標(biāo)識(shí),它告訴InterBase語(yǔ)句中列出的所有的影像文件均被組織在該標(biāo)識(shí)之下扼脐,影像文件的擴(kuò)展名是.shd岸军。另外,該語(yǔ)句創(chuàng)建的的影像總是你正在連接的當(dāng)前數(shù)據(jù)庫(kù)的影像瓦侮。影像文件的名字并不能代表它是哪個(gè)數(shù)據(jù)庫(kù)的影像艰赞,但是使用數(shù)據(jù)庫(kù)的名字給影像文件命名,便于理解肚吏、查看和管理方妖。簡(jiǎn)而言之,創(chuàng)建單一文件的Shadow罚攀,范例命令如下:

Create Shadow 1 ‘Employee.Shd’;

更加復(fù)雜的多文件Shadow則參看參數(shù)說(shuō)明即可党觅。

在我們的程序中雌澄,這樣的命令其實(shí)是放在一個(gè)ibQuery控件中,該ibQuery也如同其它的查詢的執(zhí)行那樣杯瞻,需要關(guān)聯(lián)一個(gè)IBDataBase和IBTransaction镐牺,與實(shí)際的數(shù)據(jù)庫(kù)相連接。值得指出的是魁莉,Create Shadow也在Transaction的控制下任柜,當(dāng)我們Commit Transaction的時(shí)候,鏡像數(shù)據(jù)庫(kù)才確實(shí)的創(chuàng)建出來(lái)沛厨。

在我們的程序中,Shadow維護(hù)的功能一般和其它的數(shù)據(jù)庫(kù)維護(hù)功能放在一起摔认。不過(guò)逆皮,在系統(tǒng)的自動(dòng)備份恢復(fù)功能中,也往往包含這方面的代碼参袱,因?yàn)楫?dāng)我們重整數(shù)據(jù)庫(kù)后电谣,我們可以藉次刪除并從新創(chuàng)建Shadow,保證新的Shadow本身也是健康無(wú)礙的抹蚀。

用InterBase /FireBird構(gòu)建專業(yè)級(jí)別的業(yè)務(wù)系統(tǒng)——高級(jí)Delphi篇

在后MIS時(shí)代剿牺,BS模式的商用軟件的囂塵逐漸降溫,傳統(tǒng)的GUI形態(tài)的軟件仍然散發(fā)著相當(dāng)?shù)镊攘啡溃还苁荂lient/Server晒来,還是Multi-tier,還是Smart Client郑现。這樣一來(lái)湃崩,我們親愛(ài)的Delphi和VCL則被證實(shí)為仍舊有著寶貴的價(jià)值,這種價(jià)值接箫,甚至于可以通過(guò)某些技術(shù)體現(xiàn)到IE中去攒读,這將是后面將要闡述的Rich Client。不過(guò)辛友,一切的一切還得從最基礎(chǔ)做起薄扁,那就是Delphi的數(shù)據(jù)訪問(wèn)技術(shù)和數(shù)據(jù)庫(kù)GUI設(shè)計(jì),這部分也是本書的精華所在废累。

基本把式——ClientDataSet+DataSetProvider+ibQuery

任何武功秘籍都必然有一個(gè)基本的套路邓梅,用Delphi開(kāi)發(fā)InterBase /FireBird數(shù)據(jù)庫(kù)系統(tǒng)同樣如此。我們假定讀者已經(jīng)是具備相當(dāng)經(jīng)驗(yàn)的Delphi開(kāi)發(fā)者了九默,因此我們一上來(lái)就直接把核心套路和盤托出:ClientDataSet+DataSetProvider+ibQuery震放。在對(duì)這一組合進(jìn)行深入論述之前,我們非常有必要將Delphi的數(shù)據(jù)庫(kù)訪問(wèn)方式的演化過(guò)程簡(jiǎn)要的回顧一下驼修。

Borland公司早期的Paradox數(shù)據(jù)庫(kù)取得了巨大的成功殿遂,后來(lái)又并購(gòu)了dBase诈铛,在那時(shí),Borland公司便將兩種數(shù)據(jù)庫(kù)的核心統(tǒng)一了起來(lái)墨礁,形成了BDE數(shù)據(jù)庫(kù)引擎幢竹。在進(jìn)軍Client/Server市場(chǎng)的時(shí)候,Borland公司的研發(fā)團(tuán)隊(duì)以BDE為基礎(chǔ)進(jìn)行了深入的強(qiáng)化恩静,形成了SQL Links焕毫。由于BDE/SQL Links最初起源于Paradox,所以這一數(shù)據(jù)庫(kù)引擎有著很深的Paradox的烙印驶乾,以至于這一數(shù)據(jù)庫(kù)訪問(wèn)方式很多內(nèi)部處理數(shù)據(jù)方式都是運(yùn)用了Paradox的底層功能邑飒。這個(gè)時(shí)期Delphi訪問(wèn)大型數(shù)據(jù)庫(kù)都是通過(guò)TDataBase、TTable级乐、TQuery等控件疙咸,這個(gè)時(shí)期的Delphi數(shù)據(jù)庫(kù)訪問(wèn)方式的特點(diǎn)就是——以數(shù)據(jù)引擎為核心,什么東西都是現(xiàn)在數(shù)據(jù)庫(kù)引擎中(主要指BDE)风科,此時(shí)撒轮,在Delphi的數(shù)據(jù)訪問(wèn)對(duì)象定義中,作為核心概念之一的“數(shù)據(jù)集”(TDataSet)也是密切與BDE綁定贼穆,作為數(shù)據(jù)集抽象的實(shí)現(xiàn)题山,例如TTable、TQuery故痊,它們的很多功能也是密切綁定BDE顶瞳,或者說(shuō)根本就是通過(guò)BDE來(lái)實(shí)現(xiàn)的。

在后續(xù)的發(fā)展中崖蜜,Delphi內(nèi)引入了BDE以外的其它訪問(wèn)方式浊仆,包括ADO和IBX等,這時(shí)豫领,“數(shù)據(jù)集”(TDataSet)早已和BDE脫開(kāi)抡柿,使得基于TDataSet的多種數(shù)據(jù)訪問(wèn)方式的出現(xiàn)成為可能。在這個(gè)過(guò)程中等恐,發(fā)生了一個(gè)微妙的需求洲劣,原先的BDE中的TDataSet的實(shí)現(xiàn),諸如TTable和TQuery课蔬,擁有著豐富的功能囱稽,而新的數(shù)據(jù)庫(kù)訪問(wèn)控件中的TDataSet的后代,不得不從新實(shí)現(xiàn)一遍TDataSet二跋,盡量多的實(shí)現(xiàn)TDataSet的功能子集战惊。然而實(shí)際上,TDataSet這個(gè)抽象對(duì)象規(guī)定的大部分功能特性扎即,其實(shí)與具體的數(shù)據(jù)訪問(wèn)方式吞获、訪問(wèn)引擎并無(wú)直接關(guān)系况凉,如果每當(dāng)新開(kāi)發(fā)一套數(shù)據(jù)庫(kù)控件,就得從新實(shí)現(xiàn)一遍TDataSet各拷,那么這就成為了無(wú)謂的重復(fù)了刁绒。能不能推出一個(gè)最完備、豐富的TDataSet的實(shí)現(xiàn)烤黍,而這個(gè)實(shí)現(xiàn)卻與具體的數(shù)據(jù)庫(kù)訪問(wèn)方式無(wú)關(guān)呢知市?事實(shí)上Delphi開(kāi)發(fā)團(tuán)隊(duì)也正是做了這樣的努力。最初僅用于多層系統(tǒng)的ClientDataSet速蕊,后來(lái)被推廣成為了數(shù)據(jù)庫(kù)訪問(wèn)的通用對(duì)象嫂丙,并被持續(xù)加強(qiáng),它就是與數(shù)據(jù)訪問(wèn)方式無(wú)關(guān)的最完整的TDataSet實(shí)現(xiàn)规哲。而ClientDataSet直接配合具體數(shù)據(jù)訪問(wèn)控件的用法奢入,就是ClientDataSet+DataSetProvider+具體的數(shù)據(jù)訪問(wèn)控件,在本書中媳叨,數(shù)據(jù)訪問(wèn)控件就是ibQuery」厍辏回顧歷史糊秆,我們發(fā)現(xiàn)這種三合一的組合其實(shí)就是實(shí)現(xiàn)了老的TTable。

Delphi技術(shù)支持人員后來(lái)便一直推薦使用這種三合一模式來(lái)操作數(shù)據(jù)议双,在這個(gè)時(shí)期痘番,Delphi的數(shù)據(jù)引擎的風(fēng)格出現(xiàn)了一種風(fēng)格趨勢(shì),那就是讓數(shù)據(jù)庫(kù)引擎盡量輕便平痰、精煉汞舱、簡(jiǎn)化,而把功能性的東西全都推給ClientDataSet來(lái)實(shí)現(xiàn)宗雇,從而形成了“瘦引擎昂芜、胖內(nèi)存數(shù)據(jù)集(ClientDataSet)”的局面。其中赔蒲,逐漸成為新的Delphi數(shù)據(jù)訪問(wèn)核心的DB Express(DBX)引擎泌神,就是這種思想的集中體現(xiàn)。在DBX中舞虱,數(shù)據(jù)庫(kù)訪問(wèn)引擎就是一個(gè)精煉的動(dòng)態(tài)庫(kù)欢际,DBX的控件則是一個(gè)最為簡(jiǎn)陋的單方向Query控件,這個(gè)單向Query控件矾兜,除了提供數(shù)據(jù)损趋、執(zhí)行SQL以外,沒(méi)有任何額外的功能椅寺,它的最大用途就是和DataSetProvider相配合浑槽,被ClientDataSet連接使用蒋失,一切功能的實(shí)現(xiàn)都推給了ClientDataSet。對(duì)于InterBase/FireBird開(kāi)發(fā)括荡,三合一模式中高镐,單向DBX的Query變成了IBQuery,也體現(xiàn)著相同的思想畸冲。

在這里嫉髓,我們不妨深入對(duì)比一下兩種基于數(shù)據(jù)集的數(shù)據(jù)訪問(wèn)方式:

TTable控件

胖?jǐn)?shù)據(jù)庫(kù)引擎

數(shù)據(jù)庫(kù)

傳統(tǒng)的方式

傳統(tǒng)模式下僻爽,DataSet和遠(yuǎn)端的數(shù)據(jù)庫(kù)保持著實(shí)時(shí)的互動(dòng)赶站,客戶端每做一個(gè)數(shù)據(jù)更改操作,都會(huì)立即反應(yīng)到服務(wù)器

ClientDataSet

瘦數(shù)據(jù)庫(kù)引擎

數(shù)據(jù)庫(kù)

新的方式

單向

Query

Provider

ClientDataSet和數(shù)據(jù)庫(kù)服務(wù)器的耦合更加松散郑诺,數(shù)據(jù)更改被緩存到了內(nèi)存中苫耸,在提交數(shù)據(jù)更改的時(shí)候州邢,這些更改被批量的執(zhí)行到服務(wù)器端

我們現(xiàn)在深入論述一下兩種方式的區(qū)別所在。在Client/Server思想初步取代 “小型機(jī)—終端”模式的時(shí)期褪子,Delphi中的數(shù)據(jù)集的概念來(lái)源于數(shù)據(jù)庫(kù)服務(wù)器的“游標(biāo)”(Cursor)概念量淌,在Delphi中執(zhí)行一條SQL Select語(yǔ)句后,就會(huì)在數(shù)據(jù)庫(kù)服務(wù)器端產(chǎn)生一個(gè)游標(biāo)嫌褪,而在Delphi中則體現(xiàn)出一個(gè)數(shù)據(jù)集呀枢。BDE則是利用Paradox內(nèi)存表在客戶端的引擎中實(shí)現(xiàn)了客戶端游標(biāo),那么在客戶段展現(xiàn)或操作這個(gè)數(shù)據(jù)集的數(shù)據(jù)時(shí)笼痛,服務(wù)器端的游標(biāo)就會(huì)長(zhǎng)期存在裙秋,實(shí)踐證明,這種機(jī)制要耗費(fèi)更多的服務(wù)器資源缨伊,并且使客戶端和數(shù)據(jù)庫(kù)服務(wù)器形成無(wú)意義的緊耦合摘刑,畢竟,數(shù)據(jù)一經(jīng)提供給客戶端刻坊,那么數(shù)據(jù)庫(kù)服務(wù)器就已經(jīng)完成了任務(wù)枷恕,從而沒(méi)有必要一直在那里等著客戶端關(guān)閉數(shù)據(jù)才釋放。ClientDataSet在這方面體現(xiàn)著和老的方式最大的區(qū)別:當(dāng)ClientDataSet被打開(kāi)的時(shí)候谭胚,它會(huì)向DataSetProvider申請(qǐng)數(shù)據(jù)活尊;DataSetProvider把關(guān)聯(lián)的DataSet(往往是單向Query)打開(kāi),遍歷該DataSet漏益,把所有記錄生成數(shù)據(jù)包蛹锰,關(guān)閉后面的DataSet,然后把生成的數(shù)據(jù)包發(fā)送給ClientDataSet绰疤;ClientDataSet解析并呈現(xiàn)這些數(shù)據(jù)铜犬。這個(gè)過(guò)程中,我們尤其要注意到,DataSetProvider提供數(shù)據(jù)之后癣猾,會(huì)立即關(guān)閉關(guān)聯(lián)的Query控件敛劝,這樣,當(dāng)ClientDataSet呈現(xiàn)數(shù)據(jù)的時(shí)候纷宇,Query控件早就被關(guān)閉了夸盟,也就是說(shuō),數(shù)據(jù)庫(kù)服務(wù)器上面的Cursor早就被釋放像捶,毫無(wú)疑問(wèn)上陕,這種方式要健康的多、靈活的多拓春。這里需要特別指出的是释簿,DataSetProvider有個(gè)屬性叫做“ResolveToDataSet”,我們這里假定該屬性是默認(rèn)的關(guān)閉狀態(tài)硼莽。

在數(shù)據(jù)的更改庶溶、更新方面,最傳統(tǒng)的模式懂鸵,就是數(shù)據(jù)集內(nèi)的數(shù)據(jù)一旦被更改偏螺,便會(huì)立即反映回?cái)?shù)據(jù)庫(kù)端,而ClientDataSet則是把更改保存在內(nèi)存中匆光,在提交的時(shí)候批量執(zhí)行更新語(yǔ)句砖茸。實(shí)際上后來(lái)的傳統(tǒng)模式也提供了CachedUpdates這種批量更新的功能,也能讓數(shù)據(jù)在用戶完成一系列更改之后殴穴,批量將更改提交給數(shù)據(jù)庫(kù),特別是货葬,很多DataSet后代控件具備諸如UpdateObject這樣的屬性采幌,使之能關(guān)聯(lián)一個(gè)XXXUpdateSQL,設(shè)定Insert震桶、Update休傍、Delete三種動(dòng)作相應(yīng)的參數(shù)SQL語(yǔ)句,當(dāng)提交更改的時(shí)候蹲姐,根據(jù)更改去執(zhí)行相應(yīng)的SQL語(yǔ)句磨取。這種模式其實(shí)已經(jīng)具備了ClientDataSet的主要優(yōu)點(diǎn),在一些場(chǎng)合可以替代ClientDataSet柴墩。不過(guò)它和ClientDataSet相比忙厌,仍有3個(gè)關(guān)鍵的區(qū)別:

其一,帶有批量更新功能的Query控件江咳,仍然需要數(shù)據(jù)庫(kù)服務(wù)器端的Cursor和數(shù)據(jù)集本身同時(shí)存亡逢净,沒(méi)有和數(shù)據(jù)庫(kù)服務(wù)器徹底的放松捆綁。

其二,帶有批量更新功能的Query控件不是一個(gè)完備的TDataSet類的實(shí)現(xiàn)爹土,TDataSet抽象類定義的功能集對(duì)于Query控件來(lái)說(shuō)很可能僅僅實(shí)現(xiàn)了有限的一部分甥雕;而ClientDataSet則是TDataSet的完備而豐富的實(shí)現(xiàn),功能上是TDataSet的超集胀茵。

其三社露、批量更新功能在ClientDataSet中被完整的展開(kāi)實(shí)現(xiàn)了,可以被充分的定制化琼娘,甚至于可以用程序代碼自定義數(shù)據(jù)更新的動(dòng)作峭弟。

我們充分的明白了ClientDataSet+DataSetProvider+Query模式的來(lái)由和背景之后,就可以進(jìn)入下一個(gè)環(huán)節(jié):更加深入的在實(shí)戰(zhàn)中運(yùn)用這種模式轨奄。

背景:一般情況孟害,連接數(shù)據(jù)感知控件的場(chǎng)合都推薦用ClientDataSet+DataSetProvider+Query模式,讓DataSource和ClientDataSet相關(guān)聯(lián)挪拟。

能不能更快一些挨务?——InterBase /FireBird面向性能編程

對(duì)于批量數(shù)據(jù)處理而言,“性能”一詞幾乎是個(gè)永恒的話題玉组。無(wú)論是客戶谎柄,還是我們開(kāi)發(fā)人員自身,都在不停的問(wèn):這個(gè)系統(tǒng)能不能更快一些惯雳?很多時(shí)候朝巫,我們的做好系統(tǒng)在用戶現(xiàn)場(chǎng)爆發(fā)的問(wèn)題已經(jīng)不是“能否快一些”的事情了,而是“慢得根本就不能使用石景,能否先讓我們能用起來(lái)”劈猿。作為最優(yōu)秀的構(gòu)架師來(lái)說(shuō),他的60%的水平潮孽,都要體現(xiàn)為讓系統(tǒng)給人感覺(jué)“健步如飛”揪荣。系統(tǒng)的性能的制約因素分為兩個(gè)來(lái)源:

1、? 高效率的實(shí)現(xiàn)代碼

2往史、? 面向性能的優(yōu)良的設(shè)計(jì)藝術(shù)

對(duì)于本章的內(nèi)容來(lái)說(shuō)仗颈,我們的重點(diǎn)落在了前者上。首先我們要保證我們的基本操作的實(shí)現(xiàn)代碼是最高效的椎例,這是一切的基礎(chǔ)挨决。

編寫高效率的批量數(shù)據(jù)傳輸代碼

開(kāi)發(fā)人員頻繁的需要把一大批數(shù)據(jù)從一個(gè)數(shù)據(jù)庫(kù)中復(fù)制到另一個(gè)數(shù)據(jù)庫(kù)中,這種特定的功能模式订歪,我們不妨稱之為“數(shù)據(jù)管道”程序脖祈,在業(yè)界,通常把它們叫做Replicator刷晋。這種東西是溝通不同的數(shù)據(jù)庫(kù)的最常用的方法撒犀,因而福压,對(duì)于InterBase/FireBird而言,必然會(huì)涉及這方面的內(nèi)容或舞。對(duì)于數(shù)據(jù)管道程序而言荆姆,它們的原理往往很簡(jiǎn)單,無(wú)非是把數(shù)據(jù)從一個(gè)地方取出映凳,然后插入到另一個(gè)地方胆筒。然而,由于數(shù)據(jù)量的巨大诈豌,貌似很簡(jiǎn)單的東西其實(shí)也有很關(guān)鍵的注意事項(xiàng)仆救。這里,我們先把正確的典型的做法加以論述矫渔。假定xxx.gdb數(shù)據(jù)庫(kù)中彤蔽,有一個(gè)表T1,有6個(gè)字段:id庙洼、A顿痪、B、C油够、D蚁袭、E,我們需要把某個(gè)地方的10萬(wàn)條數(shù)據(jù)插入到這個(gè)表中石咬,那么應(yīng)該這樣做:

首先和往常一樣揩悄,窗體上放好ibx的連接組件,添加一個(gè)ibQuery鬼悠,里面寫:

INSERT INTO T1(ID,A,B,C,D,E) VALUES(:ID,:A,:B,:C,:D,:E)

循環(huán)體删性,可能是for語(yǔ)句,也可能是針對(duì)某數(shù)據(jù)集的While語(yǔ)句

然后焕窝,這樣編寫數(shù)據(jù)插入函數(shù)(不妨叫做數(shù)據(jù)管道函數(shù)):

每隔256條記錄蹬挺,Commit一次

參數(shù)的賦值

如果不希望程序失去響應(yīng),則加入這句話

IBDatabase1.Open;?

ibqAddRec.Prepare;?

for I := 1 to 100000 do begin?

ibqAddRec.Params[0].Value? := …;?

ibqAddRec.Params[1].Value? := …;?

ibqAddRec.ExecSQL;?

if (I and $FF) = 0 then begin?

IBTransaction1.CommitRetaining;?

Application.ProcessMessages;?

end;?

end;?

IBTransaction1.CommitRetaining;?

IBDatabase1.Close;?

在上述很簡(jiǎn)單的代碼中

將Midas和InterBase/FireBird結(jié)合起來(lái)的封裝藝術(shù)

Delphi的Midas是一個(gè)非常關(guān)鍵的數(shù)據(jù)庫(kù)開(kāi)發(fā)組件袜啃。我們可以充分的把Midas的高級(jí)特性和InterBase/FireBird數(shù)據(jù)庫(kù)的精化結(jié)合起來(lái),達(dá)到完美境界的數(shù)據(jù)邏輯封裝效果幸缕。我們不妨給出一個(gè)極端的例子群发。

在數(shù)據(jù)庫(kù)中有這樣一個(gè)表:

R

C

DATA

1

1

XXXXX

1

2

XXXX

1

3

XXXX

1

4

XXXX

2

1

XXX

2

2

XXXX

2

3

XXX

2

4

XXXXX

我們可以看到這個(gè)表有三個(gè)字段,R(INTEGER)发乔、C(INTEGER)熟妓、Data(VARCHAR(20))。其中R代表“行”栏尚,C代表“列”起愈,這個(gè)表中的數(shù)據(jù)永遠(yuǎn)是4*N條,而R的值將是從1到4,這些數(shù)據(jù)來(lái)源于下面一張邏輯表:

R

DATA1

DATA2

DATA3

DATA4

1

XXX

XXX

XX

XXXXX

2

XXXXXXX

XXX

XXXX

XXXX

這個(gè)例子的含義不難理解抬虽,就好比是學(xué)校的學(xué)生站隊(duì)做操一樣官觅,學(xué)生本來(lái)是按照一列縱隊(duì)的形式存儲(chǔ),但是做操的時(shí)候阐污,需要讓他們站成4列縱隊(duì)休涤。那么我們這個(gè)案例中,數(shù)據(jù)在數(shù)據(jù)庫(kù)中的存儲(chǔ)形式是1列縱隊(duì)笛辟,現(xiàn)在需要把這些數(shù)據(jù)按照4列縱隊(duì)的方式展現(xiàn)開(kāi)來(lái)功氨,實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)形式和表現(xiàn)形式的完全分離,讓數(shù)據(jù)在界面上完全像一個(gè)5列的數(shù)據(jù)集那樣給最終用戶展現(xiàn)手幢,這個(gè)極端的例子即可很好的演示Midas和InterBase/FireBird高級(jí)特性相結(jié)合的藝術(shù)捷凄。下面我們就詳細(xì)的看看具體實(shí)現(xiàn)技巧。

這個(gè)物理表的DDL如下:

CREATE TABLE DEMO1 (

R???? INTEGER NOT NULL,

C???? INTEGER NOT NULL,

DATA? VARCHAR(20));

ALTER TABLE DEMO1 ADD CONSTRAINT PK_DEMO1 PRIMARY KEY (R, C);

首先围来,怎樣生成目標(biāo)形態(tài)的數(shù)據(jù)集呢跺涤?精通InterBase/FireBird的SQL語(yǔ)句的讀者可以想到,用一條復(fù)雜一點(diǎn)的嵌套式SQL語(yǔ)句即可很好的生成管钳。我們觀賞一下這樣的SQL語(yǔ)句怎么寫:

SELECT DISTINCT

R AS R_MAIN,

DATA AS DATA1,

我們可以看到钦铁,這條SQL語(yǔ)句中運(yùn)用了嵌套規(guī)則,用了三個(gè)子select才漆,三個(gè)子select中與主select的行相關(guān)聯(lián)牛曹。

(SELECT

DEMO1.DATA

FROM

DEMO1

WHERE

(DEMO1.R = DEMO_MAIN.R) AND

(DEMO1.C = 2)

) AS DATA2,

(SELECT

DEMO1.DATA

FROM

DEMO1

WHERE

(DEMO1.R = DEMO_MAIN.R) AND

(DEMO1.C = 3)

) AS DATA3,

(SELECT

DEMO1.DATA

FROM

上述復(fù)合SQL語(yǔ)句執(zhí)行的結(jié)果如下。我們發(fā)現(xiàn)醇滥,這個(gè)SQL語(yǔ)句很好的達(dá)到了我們的要求

DEMO1

WHERE

(DEMO1.R = DEMO_MAIN.R) AND

(DEMO1.C = 4)

) AS DATA4

FROM

DEMO1 AS DEMO_MAIN

WHERE

(DEMO_MAIN.C = 1)

我們?cè)贗BExpert執(zhí)行一下黎比,看看效果。

原始物理數(shù)據(jù)形態(tài)

我們看到鸳玩,果真在這個(gè)復(fù)雜的SQL的執(zhí)行下阅虫,數(shù)據(jù)按照我們所希望的樣子,由1列縱隊(duì)變成了4列縱隊(duì)不跟⊥堑郏看到這里,我們非常驚嘆于InterBase/FireBird所提供的豐富的SQL功能窝革。然而购城,這個(gè)復(fù)雜的SQL語(yǔ)句并非我們?cè)谙乱徊降难菔局幸玫模酉聛?lái)虐译,我們要看看比SQL語(yǔ)句更加豐富的FireBird存儲(chǔ)過(guò)程瘪板,實(shí)現(xiàn)這一功能。我們編寫下面一個(gè)存儲(chǔ)過(guò)程:

CREATE PROCEDURE DEMO

RETURNS (

R INTEGER,

DATA1 VARCHAR(20),

DATA2 VARCHAR(20),

DATA3 VARCHAR(20),

DATA4 VARCHAR(20))

AS

BEGIN

FOR

SELECT DISTINCT

R,

DATA AS DATA1

FROM DEMO1

WHERE (C = 1)

INTO :R,:DATA1

DO

BEGIN

SELECT? DEMO1.DATA

FROM DEMO1

WHERE

(DEMO1.R = :R) AND (DEMO1.C = 2)

INTO DATA2;

SELECT DEMO1.DATA

FROM DEMO1

WHERE

(DEMO1.R = :R) AND (DEMO1.C = 3)

INTO DATA3;

SELECT DEMO1.DATA

FROM DEMO1

WHERE

(DEMO1.R = :R) AND (DEMO1.C = 4)

INTO DATA4;

SUSPEND;

END

END

我們?cè)贗BExpert中運(yùn)行一下這個(gè)存儲(chǔ)過(guò)程漆诽,發(fā)現(xiàn)它和剛才那個(gè)復(fù)雜的SQL實(shí)現(xiàn)了完全相同的效果侮攀。不過(guò)我們看到存儲(chǔ)過(guò)程里實(shí)現(xiàn)這類的功能模塊锣枝,幾乎是手到擒來(lái)。在SQL 語(yǔ)句中是頗有些繁瑣的東西兰英,在存儲(chǔ)過(guò)程中只不過(guò)是最基礎(chǔ)的功能。在這個(gè)存儲(chǔ)過(guò)程中税朴,我們?cè)谝粋€(gè)for循環(huán)中家制,把后三列的值輕而易舉的用3個(gè)select語(yǔ)句選了出來(lái)颤殴,然后放到三個(gè)列變量中,提交杈绸。有了存儲(chǔ)過(guò)程矮瘟,我們幾乎可以生成任意的數(shù)據(jù)集,InterBase/FireBird的這個(gè)功能既強(qiáng)大劫侧,又靈活哨啃。OK烧栋!我們?cè)贒elphi程序中把數(shù)據(jù)體現(xiàn)出來(lái):

1、? 用IBDatabase將數(shù)據(jù)庫(kù)連接好

2拳球、? 取一個(gè)IBQuery控件审姓,里面寫下如下SQL:

select * from DEMO

其中,“DEMO”是存儲(chǔ)過(guò)程的名稱祝峻。注意魔吐,訪問(wèn)返回?cái)?shù)據(jù)集的存儲(chǔ)過(guò)程,要用IBQuery莱找,而并非存儲(chǔ)過(guò)程控件IBStoredProc酬姆。

3、? 和往常一樣宋距,我們用一個(gè)ClientDataSet和這個(gè)Query相連接轴踱,為的是取得完備的內(nèi)存表特性症脂,同時(shí)節(jié)約服務(wù)器Cursor資源谚赎。

4淫僻、? 連接一個(gè)DBGrid顯示數(shù)據(jù)。

設(shè)計(jì)時(shí)的控件連接關(guān)系

好了壶唤,我們?nèi)绱隧樌木桶?列縱隊(duì)的數(shù)據(jù)表格界面實(shí)現(xiàn)了雳灵。難道我們現(xiàn)在就可以慶祝成功了嗎?答案是:非也闸盔。很顯然悯辙,上述實(shí)現(xiàn)的僅僅是一個(gè)只能看的功能模塊。而我們需要的是一個(gè)能夠增躲撰、刪拢蛋、改的完全可維護(hù)數(shù)據(jù)的數(shù)據(jù)集行為。接下來(lái)垃瞧,就該Midas大展身手了。我們將借用Midas所提供的機(jī)制信姓,來(lái)從新定義這個(gè)虛擬的數(shù)據(jù)集的增、刪菊值、改等三種行為:

放置三個(gè)IBQuery控件,分別書寫以下語(yǔ)句

INSERT INTO DEMO1( R,? C,? DATA )

VALUES( :R,? :C,? :DATA )

UPDATE DEMO1

SET DATA = :DATA

WHERE ( R = :R ) and ( C = :C )

DELETE FROM DEMO1 WHERE ( R = :R )

我們?cè)谠O(shè)計(jì)器中選中DataSetProvider控件儿子,創(chuàng)建一個(gè)BeforeUpdateRecord事件函數(shù)蒋譬,在函數(shù)中,用子函數(shù)的形式將上述三個(gè)IBQuery控件封裝一下:

procedure TForm1.dpDemo1BeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;?

var Applied: boolean);?

procedure InsertRec(?

R: variant;?

C: variant;?

Data: variant);?

begin?

ibqInsertRec.ParamByName('R').Value??? := R;?

ibqInsertRec.ParamByName('C').Value??? := C;?

ibqInsertRec.ParamByName('DATA').Value := Data;?

ibqInsertRec.ExecSQL;?

end;

procedure UpdateRec(?

Data: variant;?

R: variant;?

C: variant);?

begin?

ibqUpdateRec.ParamByName('DATA').Value := Data;?

ibqUpdateRec.ParamByName('R').Value??? := R;?

ibqUpdateRec.ParamByName('C').Value??? := C;?

ibqUpdateRec.ExecSQL;?

end;

procedure DeleteRec(R: variant);?

begin?

ibqDeleteRec.ParamByName('R').Value := R;?

ibqDeleteRec.ExecSQL;?

end;?

begin

end;

從新定義增、刪瞬哼、改的代碼就將填入此處

好了,這個(gè)空的事件函數(shù)已經(jīng)預(yù)備好了讨越,我們很快將把必要的內(nèi)容寫入到里面。首先着逐,通過(guò)UpdateKind參數(shù)來(lái)區(qū)分三種更新動(dòng)作:

begin?

if UpdateKind = ukInsert then begin?

//增加記錄?

end else if UpdateKind = ukModify then begin?

//更改記錄?

end else if UpdateKind = ukDelete then begin?

//刪除記錄?

end;?

end;

在三種UpdateKind的狀態(tài)下,我們將分別作出相應(yīng)的數(shù)據(jù)操作秀姐。這就是在真正的從新定義虛擬的數(shù)據(jù)集針對(duì)增刪改動(dòng)作的后臺(tái)解釋代碼了。我們看看完成之后的代碼:

if UpdateKind = ukInsert then begin?

//增加記錄?

InsertRec(DeltaDS.FieldByName('R').NewValue, 1,?

DeltaDS.FieldByName('DATA1').NewValue);?

InsertRec(DeltaDS.FieldByName('R').NewValue, 2,?

DeltaDS.FieldByName('DATA2').NewValue);?

InsertRec(DeltaDS.FieldByName('R').NewValue, 3,?

DeltaDS.FieldByName('DATA3').NewValue);?

InsertRec(DeltaDS.FieldByName('R').NewValue, 4,?

DeltaDS.FieldByName('DATA4').NewValue);?

end else if UpdateKind = ukModify then begin?

//更改記錄?

if not VarIsEmpty(DeltaDS.FieldByName('DATA1').NewValue) then?

UpdateRec(DeltaDS.FieldByName('DATA1').NewValue,?

DeltaDS.FieldByName('R').OldValue, 1);?

if not VarIsEmpty(DeltaDS.FieldByName('DATA2').NewValue) then?

UpdateRec(DeltaDS.FieldByName('DATA2').NewValue,?

DeltaDS.FieldByName('R').OldValue, 2);?

if not VarIsEmpty(DeltaDS.FieldByName('DATA3').NewValue) then?

UpdateRec(DeltaDS.FieldByName('DATA3').NewValue,?

DeltaDS.FieldByName('R').OldValue, 3);?

if not VarIsEmpty(DeltaDS.FieldByName('DATA4').NewValue) then?

UpdateRec(DeltaDS.FieldByName('DATA4').NewValue,?

DeltaDS.FieldByName('R').OldValue, 4);?

end else if UpdateKind = ukDelete then begin???? //刪除記錄?

DeleteRec(DeltaDS.FieldByName('R').OldValue);?

end;?

Applied := True;

我們可以看到,上面的代碼清晰而整齊舷蟀,很容易讀懂碗殷,在這個(gè)事件里輕易的實(shí)現(xiàn)了虛擬數(shù)據(jù)集的數(shù)據(jù)更新動(dòng)作的從新定義旬牲。其中Applied := True是指告訴DataSetProvider,數(shù)據(jù)更改已經(jīng)被落實(shí)了擂橘,不必再做另外的操作了。工作做完了80%昌罩,還有一小段代碼沒(méi)有寫茎用,那就是存盤事件:

procedure TForm1.btnSaveClick(Sender: TObject);?

begin?

if cdsDemo1.State in [dsInsert, dsEdit] then?

cdsDemo1.Post;?

cdsDemo1.ApplyUpdates(0);?

IBTransaction1.CommitRetaining;?

end;

我們發(fā)現(xiàn)整個(gè)存盤(數(shù)據(jù)更新)過(guò)程,都是在一個(gè)事務(wù)中控制的。所以蒿褂,在存盤后,應(yīng)提交事務(wù)昙楚。我們運(yùn)行一下程序堪旧,發(fā)現(xiàn)增刪改完全和普通的數(shù)據(jù)集一樣析砸,界面上增加了1條記錄,存盤后會(huì)發(fā)現(xiàn)數(shù)據(jù)庫(kù)里面多了4條記錄弦疮,相反,刪除一條之后啸罢,數(shù)據(jù)庫(kù)里也相應(yīng)的減少了4條記錄。在實(shí)際的開(kāi)發(fā)中训桶,情形不一定有這么的極端,細(xì)節(jié)的要卻要比這個(gè)例子復(fù)雜一些午绳。比如,如果在保存過(guò)程中有異常赎败,則應(yīng)捕獲異常僵刮,根據(jù)異常的內(nèi)容判斷是否回滾勇吊。

在這個(gè)典型案例所揭示的技巧,就是將InterBase/FireBird的精髓功能——返回?cái)?shù)據(jù)集的存儲(chǔ)過(guò)程针史,和Delphi的數(shù)據(jù)庫(kù)精髓——Midas相結(jié)合的技巧。這樣的結(jié)合,使我們幾乎無(wú)所不能的開(kāi)發(fā)任意的數(shù)據(jù)集形態(tài)的功能模塊:用存儲(chǔ)過(guò)程生成數(shù)據(jù)竭业,用DataSetProvider的BeforeUpdateRecord事件解釋數(shù)據(jù)的更新動(dòng)作未辆。更好的是,為了開(kāi)發(fā)友好方便的界面拙友,我們的DBGrid一般都換作第三方出品的最為精致的DBGrid控件,比如說(shuō)DevExpress的cxGrid牍蜂,這樣一來(lái)鲫竞,我們封裝的ClientDataSet可以連接各種符合數(shù)據(jù)感知規(guī)范的控件,運(yùn)用大量?jī)?yōu)秀的數(shù)據(jù)感知控件赁还,也是我們把數(shù)據(jù)封裝成為數(shù)據(jù)集的一個(gè)重要意義。在實(shí)戰(zhàn)中朋蔫,數(shù)據(jù)的更新動(dòng)作被從新定義的程度不一定有這個(gè)例子這么徹底,也許僅僅定義其中的部分動(dòng)作青扔。不同的情況都會(huì)有不同注意事項(xiàng),這些凛剥,都將在以后的章節(jié)中作詳細(xì)討論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盲憎,一起剝皮案震驚了整個(gè)濱河市饼疙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌磅甩,老刑警劉巖渣聚,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓶堕,死亡現(xiàn)場(chǎng)離奇詭異谭梗,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)远舅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門盖喷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人暮刃,你說(shuō)我怎么就攤上這事⊙踱” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵柱锹,是天一觀的道長(zhǎng)丰包。 經(jīng)常有香客問(wèn)我禁熏,道長(zhǎng),這世上最難降的妖魔是什么烫沙? 我笑而不...
    開(kāi)封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任匹层,我火速辦了婚禮,結(jié)果婚禮上锌蓄,老公的妹妹穿的比我還像新娘升筏。我一直安慰自己灵汪,他們只是感情好譬胎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布苟翻。 她就那樣靜靜地躺著贴谎,像睡著了一般溯香。 火紅的嫁衣襯著肌膚如雪伐憾。 梳的紋絲不亂的頭發(fā)上廓脆,一...
    開(kāi)封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天谓晌,我揣著相機(jī)與錄音烦味,去河邊找鬼蔬芥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛良风,可吹牛的內(nèi)容都是我干的这难。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼雹锣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤席爽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后逼侦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掖鱼,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡答捕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盛泡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片来氧。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诫给,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出啦扬,到底是詐尸還是另有隱情蝙搔,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布考传,位于F島的核電站吃型,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏僚楞。R本人自食惡果不足惜勤晚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泉褐。 院中可真熱鬧赐写,春花似錦、人聲如沸膜赃。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至端铛,卻和暖如春泣矛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背禾蚕。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工您朽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人换淆。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓哗总,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親倍试。 傳聞我的和親對(duì)象是個(gè)殘疾皇子讯屈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容