文/武宗品
信息化系統(tǒng)包含信息的采集、處理、分析和統(tǒng)計(jì),在此過(guò)程中,需要進(jìn)行信息的持久化存儲(chǔ)。信息系統(tǒng)當(dāng)前大多數(shù)使用關(guān)系型數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)信息。
根據(jù)TIOBE 排行榜,Java 依然是排名第一的開(kāi)發(fā)語(yǔ)言,因此公司使用Java 開(kāi)發(fā)信息化系統(tǒng)。面向?qū)ο笫荍ava 的一大特點(diǎn),在使用面向?qū)ο蠓椒ㄟM(jìn)行系統(tǒng)開(kāi)發(fā)時(shí),需要用實(shí)體對(duì)象來(lái)表示所處理的信息。因此,就需要不斷的對(duì)信息進(jìn)行關(guān)系型數(shù)據(jù)和實(shí)體對(duì)象的互轉(zhuǎn),即所謂的對(duì)象關(guān)系映射(Object-Relational Mapping,簡(jiǎn)稱(chēng)ORM)。
目前有多種框架幫助開(kāi)發(fā)者簡(jiǎn)化ORM 的開(kāi)發(fā),例如Hiberante 和iBatis。這些框架有諸多優(yōu)勢(shì),但同時(shí)也存在天然缺陷:由于是在程序運(yùn)行時(shí)才會(huì)生產(chǎn)數(shù)據(jù)庫(kù)操作,導(dǎo)致在開(kāi)發(fā)時(shí)難以調(diào)試,難以進(jìn)行SQL 優(yōu)化。
針對(duì)上述問(wèn)題,本文提出并實(shí)現(xiàn)了一個(gè)輕量級(jí)的Java 數(shù)據(jù)庫(kù)操作組件——DatabaseOperator,該組件為開(kāi)發(fā)人員提供一個(gè)簡(jiǎn)單、高效、方便調(diào)試和優(yōu)化的數(shù)據(jù)庫(kù)操作方法。由于可以自行控制SQL 語(yǔ)句,并且無(wú)需關(guān)注JDBC 的各種狀態(tài)維護(hù),為開(kāi)發(fā)人員提供了更大的靈活性,減輕了許多冗余代碼。該組件已經(jīng)在公司開(kāi)發(fā)的多套系統(tǒng)中使用。
數(shù)據(jù)庫(kù)操作組件DatabaseOperator 為了保留調(diào)試和SQL 優(yōu)化的特性,選擇采用JDBC來(lái)直接操作數(shù)據(jù)庫(kù)。同時(shí),為了簡(jiǎn)化開(kāi)發(fā)人員的操作,降低代碼冗余,減少開(kāi)發(fā)人員對(duì)數(shù)據(jù)庫(kù)連接的維護(hù)工作,組件將采用狀態(tài)模式和觀察者模式這兩個(gè)設(shè)計(jì)模式作為設(shè)計(jì)指導(dǎo)。
Erich Gamma 等人給出了設(shè)計(jì)模式的定義,可以這樣去理解它:設(shè)計(jì)模式和語(yǔ)言無(wú)關(guān),通常是一種針對(duì)某類(lèi)問(wèn)題或場(chǎng)景,將變化的部分抽離出去,將不變的部分保留下來(lái),最終形成的一個(gè)解決問(wèn)題的套路或思考范式。本小節(jié)將對(duì)用到的兩個(gè)設(shè)計(jì)模式進(jìn)行簡(jiǎn)單介紹。

圖1:標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)操作

圖2:數(shù)據(jù)庫(kù)操作狀態(tài)
1.1.1 狀態(tài)模式
該模式的定義:狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來(lái)好像修改了它的類(lèi)。普遍的說(shuō),當(dāng)要處理的事情有不同的狀態(tài),并且在不同的狀態(tài)有不同的行為,狀態(tài)與狀態(tài)之間有明確的轉(zhuǎn)換觸發(fā)條件,對(duì)于存在這種情況的可以使用狀態(tài)模式來(lái)指導(dǎo)設(shè)計(jì),規(guī)范代碼結(jié)構(gòu)。
1.1.2 觀察者模式
該模式的定義:觀察者模式定義了對(duì)象之間的一對(duì)多依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí),它的所有依賴(lài)者都會(huì)收到通知并自動(dòng)更新。普遍的說(shuō),當(dāng)要處理的事情有一個(gè)明確的第三方,該第三方需要獲取相關(guān)對(duì)象的行為,并在全部或者某些行為時(shí)第三方有自己的行動(dòng),對(duì)于存在這種情況的可以使用觀察者模式來(lái)指導(dǎo)設(shè)計(jì)。
Java 數(shù)據(jù)庫(kù)連接,(Java Database Connectivity,簡(jiǎn)稱(chēng)JDBC)是Java 語(yǔ)言中用來(lái)規(guī)范客戶(hù)端程序如何來(lái)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用程序接口,提供了諸如查詢(xún)和更新數(shù)據(jù)庫(kù)中數(shù)據(jù)的方法。
本小節(jié)首先介紹標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)操作方法,然后通過(guò)分析,設(shè)計(jì)出一套簡(jiǎn)潔高效的數(shù)據(jù)庫(kù)操作組件并進(jìn)行實(shí)現(xiàn)。
如圖1所示,是一個(gè)Java 上的標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)操作步驟:①定義變量;②連接數(shù)據(jù)庫(kù);③業(yè)務(wù)操作(本例是一個(gè)最簡(jiǎn)單的業(yè)務(wù)查詢(xún)操作);④處理業(yè)務(wù)異常;⑤關(guān)閉數(shù)據(jù)庫(kù)連接。
上節(jié)所介紹的標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)操作中,對(duì)于開(kāi)發(fā)人員需要關(guān)注的只有“③業(yè)務(wù)操作”這一部分,可以看到其余都是無(wú)需關(guān)注的,如何抽離那些無(wú)需關(guān)注的而只保留需要關(guān)注的部分是實(shí)現(xiàn)組件的關(guān)鍵。
通過(guò)分析,可知在操作數(shù)據(jù)庫(kù)的時(shí)候,經(jīng)歷了如下幾個(gè)步驟:參數(shù)初始化;連接數(shù)據(jù)庫(kù);處理業(yè)務(wù);完成并關(guān)閉。在每一個(gè)步驟中,都會(huì)有不同的操作,并且步驟之間的轉(zhuǎn)換都是通過(guò)固定的操作來(lái)完成的。針對(duì)這種場(chǎng)景,使用“狀態(tài)模式”來(lái)進(jìn)行設(shè)計(jì):將數(shù)據(jù)庫(kù)操作的每一步都看作一個(gè)狀態(tài),在獨(dú)立的狀態(tài)中,只需關(guān)注當(dāng)前狀態(tài)要做的事情,狀態(tài)與狀態(tài)之間的轉(zhuǎn)換,交給幾個(gè)專(zhuān)門(mén)的處理方法來(lái)完成即可。圖1所示的數(shù)據(jù)庫(kù)操作只是基本的業(yè)務(wù)查詢(xún)操作,考慮到還有批量操作、存儲(chǔ)過(guò)程操作和事務(wù)操作,最終設(shè)計(jì)的狀態(tài)機(jī)如圖2所示:init(初始狀態(tài));transaction(事務(wù)狀態(tài));sqlDone(業(yè)務(wù)狀態(tài));callable(存儲(chǔ)過(guò)程狀態(tài));batch(批量業(yè)務(wù)狀態(tài))。觸發(fā)狀態(tài)轉(zhuǎn)換的操作有:startTransaction,開(kāi)啟事務(wù);commit,提交事務(wù);setSql,設(shè)定數(shù)據(jù)庫(kù)操作語(yǔ)句;setPS,動(dòng)態(tài)SQL 參數(shù);execute/query,增刪改查;setCallable,設(shè)定存儲(chǔ)過(guò)程;setCallableHandler,設(shè)定存儲(chǔ)過(guò)程回掉;addSql,添加批量SQL;addBatch,添加批量操作;executeBatch,執(zhí)行批量操作;end,結(jié)束操作。

圖3:實(shí)現(xiàn)
通過(guò)分析,數(shù)據(jù)庫(kù)在操作的過(guò)程中,為了讓開(kāi)發(fā)人員專(zhuān)注于業(yè)務(wù),而無(wú)需關(guān)注和維護(hù)當(dāng)前數(shù)據(jù)庫(kù)連接的建立與關(guān)閉,需要有第三方來(lái)監(jiān)控現(xiàn)在的操作狀態(tài),并在操作結(jié)束時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接、回收對(duì)象。針對(duì)這種場(chǎng)景,使用“觀察者模式”來(lái)指導(dǎo)設(shè)計(jì):當(dāng)開(kāi)始進(jìn)行數(shù)據(jù)庫(kù)操作的時(shí)候,監(jiān)控對(duì)象訂閱數(shù)據(jù)庫(kù)操作對(duì)象的通知,數(shù)據(jù)庫(kù)操作結(jié)束時(shí)發(fā)出通知,監(jiān)控對(duì)象負(fù)責(zé)完成關(guān)閉數(shù)據(jù)庫(kù)連接和回收對(duì)象的工作。
根據(jù)分析與設(shè)計(jì),數(shù)據(jù)庫(kù)操作組件的實(shí)現(xiàn)如圖3所示。
開(kāi)發(fā)人員在使用該組件的時(shí)候,需要操作圖1所示的業(yè)務(wù)時(shí),實(shí)際代碼如圖4所示。由此可見(jiàn),不僅保留了SQL 的可調(diào)式性,也大大減少了開(kāi)發(fā)的工作量。
在結(jié)合了狀態(tài)模式和觀察者模式之后,對(duì)JDBC 進(jìn)行了重新的封裝,完成了DatabaseOperator 數(shù)據(jù)庫(kù)操作組件的開(kāi)發(fā)。使用該組件,無(wú)需引用大量的框架,能夠快速搭建信息系統(tǒng),簡(jiǎn)化代碼工作量,保持SQL 可調(diào)式,確保數(shù)據(jù)庫(kù)優(yōu)化的可控性,為公司多個(gè)項(xiàng)目的開(kāi)發(fā)提高了效率,降低了出錯(cuò)率。同時(shí),在實(shí)踐中也發(fā)現(xiàn)該組件還有可以不斷優(yōu)化的地方,例如:與數(shù)據(jù)庫(kù)的連接除了自己創(chuàng)建之外,還可以交給數(shù)據(jù)庫(kù)連接池來(lái)進(jìn)行管理,從而提高連接效率;數(shù)據(jù)查詢(xún)后的結(jié)果,可以使用反射機(jī)制將查詢(xún)后的結(jié)果直接轉(zhuǎn)變成對(duì)象。

圖4:使用組件后的數(shù)據(jù)庫(kù)操作