歐陽宏基,葛 萌
(咸陽師范學(xué)院 計(jì)算機(jī)學(xué)院,咸陽 712000)
數(shù)據(jù)初始化是任何一個應(yīng)用系統(tǒng)運(yùn)行其業(yè)務(wù)邏輯的基礎(chǔ).初始化的數(shù)據(jù)一般都是基礎(chǔ)數(shù)據(jù),由當(dāng)前應(yīng)用系統(tǒng)的需求分析而確定.一部分?jǐn)?shù)據(jù)需要自行定義,一部分可能來自于和當(dāng)前系統(tǒng)相關(guān)的其他業(yè)務(wù)系統(tǒng).初始化的數(shù)據(jù)通常在系統(tǒng)正式上線運(yùn)行前或者運(yùn)行時添加到數(shù)據(jù)庫中,是應(yīng)用系統(tǒng)中其他業(yè)務(wù)數(shù)據(jù)賴以生存的前提,因此每一個系統(tǒng)都必須執(zhí)行數(shù)據(jù)初始化的操作.目前,常見的數(shù)據(jù)初始化操作方法有兩種:一種是為系統(tǒng)各模塊提供數(shù)據(jù)添加操作,通過用戶手工方式逐條錄入所需要的數(shù)據(jù),該方法適合規(guī)模較小、基礎(chǔ)數(shù)據(jù)量少的系統(tǒng)[1].第二種方法是通過數(shù)據(jù)庫第三方工具(例如MySQL 數(shù)據(jù)庫的SQLyog、Navicat 等)將存儲在Excel、XML、HTML 等文件中或者是其他信息系統(tǒng)數(shù)據(jù)庫中的相關(guān)數(shù)據(jù)批量導(dǎo)入到當(dāng)前應(yīng)用中,該方法適合規(guī)模、數(shù)據(jù)量較大的系統(tǒng),但是在操作過程中也必須單表逐個導(dǎo)入.無論采用上述哪種方法,用戶在操作時必須按照一定的順序,尤其是基礎(chǔ)數(shù)據(jù)之間存在較復(fù)雜依賴關(guān)系的請求下,無疑增加了用戶操作的復(fù)雜度,影響了用戶的操作體驗(yàn).
針對上述問題,在研究建造者模式、策略模式以及單例模式的前提下,提出一種新的數(shù)據(jù)初始化方法,該方法在系統(tǒng)運(yùn)行前自動讀取存儲在外部相關(guān)文件中的數(shù)據(jù)并保存到當(dāng)前應(yīng)用的數(shù)據(jù)庫中,避免了手動操作的繁瑣.以高等院校目標(biāo)考核管理系統(tǒng)中的數(shù)據(jù)初始化操作為例,分析了各部分的初始化數(shù)據(jù)以及順序問題.以Excel 文件作為數(shù)據(jù)初始化前的載體,利用JXL、JDBC 和Hibernate 作為混合數(shù)據(jù)持久化技術(shù)完成了數(shù)據(jù)的初始化操作,詳細(xì)闡述了上述各設(shè)計(jì)模式的具體實(shí)現(xiàn)過程,為數(shù)據(jù)初始化操作提供了一定的參考.
設(shè)計(jì)模式(design pattern)是面向?qū)ο蠹夹g(shù)中被精心編制的接口與類的組合,在特定的應(yīng)用場景中使用特定的模式可以獲得結(jié)構(gòu)清晰、易于擴(kuò)展和理解的代碼結(jié)構(gòu)[2,3].建造者模式(Builder Pattern)屬于創(chuàng)建型模式的一種,主要用于將一個復(fù)雜對象的構(gòu)建與它的表示分離,向用戶屏蔽復(fù)雜對象組成部分的創(chuàng)建細(xì)節(jié)[4].單例模式(singleton pattern)也屬于創(chuàng)建型模式,主要用于約束某個類的對象只能被實(shí)例化一次.策略模式(strategy pattern)屬于行為型模式,該模式通常將某個行為的不同實(shí)現(xiàn)方式定義為某個單獨(dú)的類,允許調(diào)用端根據(jù)特定情況更換行為的實(shí)現(xiàn)方式[5].
基于Java EE 平臺的應(yīng)用系統(tǒng)通常利用JDBC 或Hibernate 技術(shù)進(jìn)行關(guān)系型數(shù)據(jù)庫的訪問.JDBC 通過Connection、Statement、ResultSet 等接口執(zhí)行原生SQL 語句操作數(shù)據(jù)庫[6];Hibernate 是ORM 協(xié)議的具體實(shí)現(xiàn),對JDBC 進(jìn)行了輕量級封裝,以映射文件或注解為基礎(chǔ)實(shí)現(xiàn)對象模型與數(shù)據(jù)庫表的映射,并且自動管理對象與對象之間的關(guān)聯(lián)關(guān)系[7].Hibernate 提供了Configuration、SessionFactory、Session、Transaction和Query 和Criteria 等6 個核心接口對持久化對象進(jìn)行存儲和事務(wù)控制,交互過程如圖1所示.其中,Configuration 負(fù)責(zé)讀取配置文件并創(chuàng)建SessionFactory;SessionFactory 是重量級組件采用了單例設(shè)計(jì)模式,在啟動時創(chuàng)建全局唯一對象并常駐內(nèi)容,主要用來管理Session 對象和部分緩存數(shù)據(jù).Session 對象代表了一條與數(shù)據(jù)庫的連接,用來創(chuàng)建Query 或Criteria 對象.Query 或Criteria 負(fù)責(zé)執(zhí)行HQL 語句,在Transaction 的管理下利用映射文件實(shí)現(xiàn)持久化對象與數(shù)據(jù)庫的交互[8].

圖1 Hibernate 核心接口交互圖
Java EE 應(yīng)用的初始化過程中會涉及眾多的對象,他們之間必然存在復(fù)雜的關(guān)聯(lián)關(guān)系.通過ORM 將這些對象保存到數(shù)據(jù)庫中,并維持之間的外鍵關(guān)系,就必須考慮初始化的順序問題.例如在采用BRAC 模型實(shí)現(xiàn)的權(quán)限管理系統(tǒng)中,權(quán)限、角色和用戶三者存在著關(guān)聯(lián)關(guān)系[9].角色關(guān)聯(lián)權(quán)限,用戶關(guān)聯(lián)角色,首先應(yīng)初始化權(quán)限數(shù)據(jù),再初始化角色數(shù)據(jù),最后初始化用戶數(shù)據(jù).因此,當(dāng)對象的關(guān)聯(lián)關(guān)系之間具有先后順序時,需要先保存被關(guān)聯(lián)的對象數(shù)據(jù).
綜合應(yīng)用單例、建造者、策略設(shè)計(jì)模式的數(shù)據(jù)初始化模型類圖關(guān)系如圖2所示.其中,SysData、SysData Builder、SysDataExcelBuilder 和SysDataDirector構(gòu)成建造者模式.SysData 表示產(chǎn)品,定義所有要初始化的數(shù)據(jù);SysDataBuilder 表示抽象建造者,SysData ExcelBuilder 表示具體建造者;SysDataDirector 表示指揮者,其中的construct()方法控制初始化數(shù)據(jù)的順序.JDBCUtil 為單例設(shè)計(jì)模式,該類的主要作用有兩個,①封裝加載數(shù)據(jù)庫驅(qū)動、創(chuàng)建數(shù)據(jù)庫連接和釋放資源;② 創(chuàng)建和刪除數(shù)據(jù)庫.SysInit、InitStrategy 和ConcreteStrategy 構(gòu)成策略模式.SysInit 為環(huán)境類、InitStrategy 為策略接口,ConcreteStrategy 為具體初始化策略,包括開發(fā)階段的初始化策略和系統(tǒng)部署上線運(yùn)行階段的策略.

圖2 數(shù)據(jù)初始化方法類圖
目標(biāo)考核系統(tǒng)是采用計(jì)算機(jī)與網(wǎng)絡(luò)技術(shù)所實(shí)現(xiàn)的對高校各部門年度目標(biāo)任務(wù)進(jìn)行信息化管理的Web 系統(tǒng).系統(tǒng)基于Java EE 平臺,采用MVC 模式設(shè)計(jì),由Struts2+Spring+Hibernate 輕量級框架構(gòu)建[10].核心功能包括目標(biāo)任務(wù)的編制、任務(wù)的下達(dá)、任務(wù)完成數(shù)據(jù)的上傳、任務(wù)完成數(shù)據(jù)的審核、量化打分以及匯總等功能.通過該系統(tǒng)實(shí)現(xiàn)了目標(biāo)考核工作的數(shù)字化管理,提高了考核過程的透明度、結(jié)果的公平性和公正性,對全校教職工的工作具有良好的引導(dǎo)和激勵作用,為學(xué)校領(lǐng)導(dǎo)層作決策提供了數(shù)據(jù)支撐.
由于目標(biāo)考核工作涉及較多的職能部門(發(fā)展規(guī)劃處、人事處、科技處、學(xué)生工作處、教務(wù)處、學(xué)科辦、團(tuán)委、黨委組織部、黨委宣傳部等)、各二級教學(xué)單位和全體教職工.考核目標(biāo)覆蓋了教育教學(xué)、科學(xué)研究、師資隊(duì)伍建設(shè)、學(xué)生工作、黨風(fēng)廉政建設(shè)等各個方面,因此系統(tǒng)運(yùn)行所需要的基礎(chǔ)數(shù)據(jù)較多.按照考核工作的職責(zé)、對象和任務(wù),將基礎(chǔ)數(shù)據(jù)劃分為三大部分,包括:用戶數(shù)據(jù)、權(quán)限數(shù)據(jù)和指標(biāo)數(shù)據(jù).其中用戶數(shù)據(jù)包含技術(shù)職務(wù)、黨政職務(wù)、黨政職務(wù)級別、崗位級別、部門、教工基本信息、部門賬戶和科研類別.權(quán)限數(shù)據(jù)包括權(quán)限和角色.指標(biāo)包括綜合指標(biāo)和業(yè)務(wù)指標(biāo)兩部分,每部分又細(xì)分為一級指標(biāo)、二級指標(biāo)和三級指標(biāo).其中一個一級指標(biāo)包含多個二級指標(biāo),一個二級指標(biāo)包含多個三級指標(biāo).上述各項(xiàng)數(shù)據(jù)的具體初始化先后順序依次是:技術(shù)職務(wù)、黨政職務(wù)、黨政職務(wù)級別、崗位級別、部門、權(quán)限、角色、教工基本信息、部門賬戶、科研級別、一級綜合指標(biāo)、二級綜合指標(biāo)、三級綜合指標(biāo)、業(yè)績一級指標(biāo)、二級業(yè)績指標(biāo)、三級業(yè)績指標(biāo).
建造者設(shè)計(jì)模式包括抽象建造者、具體建造者、指揮者和產(chǎn)品4 個角色,如圖3所示.將目標(biāo)考核系統(tǒng)的所有要初始化的數(shù)據(jù)看作一個整體,充當(dāng)其中的產(chǎn)品角色,每個部分的數(shù)據(jù)作為產(chǎn)品的一個成員,用List集合表示,因此產(chǎn)品是一個較復(fù)雜的POJO 對象.抽象建造者角色關(guān)聯(lián)一個受保護(hù)的產(chǎn)品對象,定義初始化各部分?jǐn)?shù)據(jù)的抽象接口,其中每一個buildXXX()方法創(chuàng)建一類要初始化的數(shù)據(jù),通過getResult()方法得到所關(guān)聯(lián)的產(chǎn)品對象.具體建造者繼承抽象建造者實(shí)現(xiàn)每一個buildXXX()方法,定義每一類數(shù)據(jù)的初始化邏輯.

圖3 建造者設(shè)計(jì)模式類圖
本文所實(shí)現(xiàn)的目標(biāo)考核系統(tǒng)的初始化數(shù)據(jù)存儲在Excel 文件中,所以定義SysDataExcelBuilder 類作為具體的建造者.其中包含每一類初始化數(shù)據(jù)對應(yīng)的Service 組件作為屬性,其對象通過@Resource 注解從Spring IOC 容器獲取.Service 對象通過@Resource 注解關(guān)聯(lián)的Dao 對象完成初始化操作,Dao 對象封裝了Hibernate API 具體負(fù)責(zé)初始化數(shù)據(jù)的增、刪、改、查操作.具體建造者通過讀取applicationContext.xml 文件創(chuàng)建Spring IOC 容器,用ApplicationContext 對象表示.另外還包含一個InputStream 對象用作讀取Excel 文件的流對象,一個Workbook 對象用來表示Excel 的工作表,通過JXL 完成對Excel 工作表和單元格數(shù)據(jù)的訪問[11].
策略設(shè)計(jì)模式包括環(huán)境、抽象策略和具體策略三個角色,如圖4所示.該模式可以根據(jù)環(huán)境或者條件的不同而選擇不同的策略來完成某項(xiàng)任務(wù).InitStrategy為抽象策略接口,其中initData 方法定義數(shù)據(jù)初始化算法.DevelopmentStrategy 和RunningStratey 是兩個具體的初始化策略,DevelopmentStrategy 是系統(tǒng)開發(fā)階段使用的策略,具體的數(shù)據(jù)初始化算法是如果數(shù)據(jù)庫存在先刪除數(shù)據(jù)庫,再創(chuàng)建數(shù)據(jù)庫并通過建造者模式的指揮者對象調(diào)用初始化操作.RunningStrategy 是系統(tǒng)部署上線運(yùn)行時采用的策略,具體的數(shù)據(jù)初始化算法是獲取初始化完成標(biāo)記信息,判斷是否已經(jīng)執(zhí)行過初始化操作,如果已經(jīng)執(zhí)行則忽略;如果沒有初始化過,那么先創(chuàng)建數(shù)據(jù)庫,通過建造者模式的指揮者對象調(diào)用初始化操作并設(shè)置初始化完成標(biāo)記,標(biāo)記信息存儲在特定數(shù)據(jù)庫表中.

圖4 策略設(shè)計(jì)模式類圖
單例設(shè)計(jì)模式能夠確保某個類只能擁有自己的一個對象,在某些工具類的定義中普遍應(yīng)用單例模式.這種工具類基本上貫穿程序始終,必然會頻繁調(diào)用.如果每一次調(diào)用都要重新生成實(shí)例,帶來的就是內(nèi)存堆空間的浪費(fèi),所以單例模式能夠提高程序的運(yùn)行速度,減少資源消耗.文獻(xiàn)[12]分析了單例模式實(shí)現(xiàn)的5 種方式,總結(jié)了每種方式的優(yōu)缺點(diǎn)和應(yīng)用場景.本初始化模型在操作數(shù)據(jù)庫時采用JDBC 與Hibernate 相結(jié)合的混合持久化技術(shù),所以采用靜態(tài)內(nèi)部類方式作為單例模式的實(shí)現(xiàn)方法,因?yàn)樵摲椒ň哂姓{(diào)用效率高、線程安全、支持延遲加載等優(yōu)點(diǎn).
由于Hibernate 框架能夠創(chuàng)建并更改數(shù)據(jù)庫表結(jié)構(gòu),實(shí)現(xiàn)對象與表、對象之間關(guān)系與表之間關(guān)聯(lián)的映射,但無法自動創(chuàng)建數(shù)據(jù)庫,因此需要通過JDBC 執(zhí)行SQL 自動創(chuàng)建數(shù)據(jù)庫.利用單例模式定義JDBCUtil,用來封裝JDBC 的加載數(shù)據(jù)庫驅(qū)動、獲取Connection對象和釋放資源等3 個操作,這個單例對象作為JDBC操作的全局唯一入口.同樣為了簡化Hibernate進(jìn)行持久化操作代碼的重復(fù)性,利用單例模式定義HibernateUtil,該類完成對Hibernate 有關(guān)代碼的封裝,其中包含的主要操作有g(shù) e t S e s s i o n F a c t o r y()、getSession()和closeSession().在各部分初始化數(shù)據(jù)對應(yīng)的泛型DAO 實(shí)現(xiàn)類中對HibernateUtil 單例對象進(jìn)行調(diào)用,完成公共的save()、delete()、update()、getById()、getByIds()和findAll()方法的邏輯.
系統(tǒng)實(shí)施所采用的相關(guān)工具信息如表1所示.

表1 系統(tǒng)相關(guān)工具信息表
要導(dǎo)入到系統(tǒng)中的初始化數(shù)據(jù)存放在Excel 文件中,共包括16 張worksheet,其中技術(shù)職務(wù)表有數(shù)據(jù)52 條、黨政職務(wù)類別表有數(shù)據(jù)6 條、黨政職務(wù)名稱表28條、崗位類別表4條、部門信息表48條、權(quán)限數(shù)據(jù)表126 條、角色表有27 條、部門賬戶表有60 條、教工信息表1248 條、科研級別表47條、一級指標(biāo)表5條、二級指標(biāo)表30條、三級指標(biāo)表109 條、業(yè)績一級指標(biāo)表6條、業(yè)績二級指標(biāo)表23條、業(yè)績?nèi)壷笜?biāo)表67條,文件總大小為680 KB.進(jìn)行開發(fā)階段的策略測試時,在JUnit 單元測試中調(diào)用初始化數(shù)據(jù)的代碼,如下代碼所示:

執(zhí)行后發(fā)現(xiàn)在MySQL 中生成了對應(yīng)的數(shù)據(jù)庫以及相應(yīng)的表,每個表中都插入了對應(yīng)Excel 工作表中的數(shù)據(jù).第二次再執(zhí)行會先刪除上次創(chuàng)建的數(shù)據(jù)庫,再重新生成數(shù)據(jù)庫及對應(yīng)的表.多次測試后平均完成初始化操作的時間為195s.針對運(yùn)行時策略的測試,由于運(yùn)行時策略在系統(tǒng)正式部署時使用,所以定義了初始化監(jiān)聽器執(zhí)行上述代碼,將具體策略換成RunningStrategy.初始化監(jiān)聽器在web.xml 中的配置位置位于Spring IOC 容器的配置后,因?yàn)橹挥蠸pring 容器初始化后,才能通過容器對象得到各部分初始化數(shù)據(jù)對應(yīng)的Service 組件.經(jīng)過測試,初始化操作會在Web 服務(wù)器啟動后自動執(zhí)行,以后再次啟動Web 服務(wù)器初始化操作不再執(zhí)行.
設(shè)計(jì)模式是面向?qū)ο蟪绦蛟O(shè)計(jì)中通用問題的一種可復(fù)用解決方案.將建造者、策略和單例模式應(yīng)用到基礎(chǔ)數(shù)據(jù)的初始化設(shè)計(jì)中,簡化了初始化操作.同時,應(yīng)用系統(tǒng)如需增加其他初始化數(shù)據(jù),只需更改產(chǎn)品、抽象建造者和具體建造者角色;如果需要從其他存儲方式中讀取初始化數(shù)據(jù),只需重新定義具體建造者角色.因此,所提出的數(shù)據(jù)初始化方法具有較高的復(fù)用性、維護(hù)性和擴(kuò)展性.