劉紅衛
(泰達圖書館檔案館 天津300457)
數據庫幾乎是信息管理系統開發中的標配。數據庫的應用,使得數據的管理井井有條,數據的利用也非常方便。在一個信息系統中一般都是訪問一個數據庫,但也有一些特殊的系統,尤其是在原有多個信息系統上建立整合的應用系統,往往要對多種類型數據庫進行訪問,以便對那些分散在異構數據庫中的數據進行協同訪問,然后再將數據重新整合進行利用。
隨著信息技術的進步,移動互聯網普遍應用,短信已經不是人們之間通訊的主要手段,但是短信以其隨身性和及時性,依然是當今作為推送服務信息不可或缺的方式。
筆者所在的圖書館自 2007年開始,應用短信系統開展圖書館服務,至今已有十多年的時間,舊的短信平臺系統是一臺中國移動定制的硬件設備,配合短信貓的使用才能做到全網短信的發送,短信的業務邏輯實現也是在這臺設備上配置的。
2018年中國移動公司將短信平臺升級為云端方式,稱為云 MAS平臺。為了繼續保持短信服務的開展,我們考察云 MAS平臺的功能,發現其只提供了普通短信的發送功能,用戶通過瀏覽器直接登錄云 MAS平臺,通過操作頁面的方式進行短信發送,沒有提供像舊版本那樣,能與本單位系統相結合來定義的業務短信的配置功能,但是提供了HTTP、SDK、CMPP等方式的短信網關接口[1],需要自行編寫程序、開發系統。新的短信服務系統的相關數據庫和網絡拓撲如圖1所示。

圖1 數據庫訪問和網絡拓撲圖Fig.1 Database access and network topology diagrams
在圖 1中,LAS服務器上運行著圖書館核心管理系統,讀者借閱和圖書單冊信息存儲在 Oracle數據庫中。eCard服務器上運行的是讀者證卡管理系統,為了避免讀者接收到無關的服務短信,讀者可以自己定制所需要的短信類型,此項功能包括在 eCard系統中,讀者信息(包括手機號碼)、讀者定制服務信息和消費信息存儲在 DB2數據庫中。短信服務器上運行短信服務管理系統,也就是需要開發的系統,需要發送的服務短信內容存放在本機的 Mysql數據庫中(在舊系統中有定制服務短信內容的Web系統,后臺是 MySql數據庫,這部分沿用,無需重新開發,如此也可以縮短新系統的開發時間)。對于讀者手機號及所借圖書的到期情況等信息,需要從 LAS的Oracle數據庫和 eCard的 DB2數據庫中提取,然后將數據組裝成一條短信內容,通過中國移動(CMCC)短信網關提供的HTTP接口發送出去,最后將相關發送情況進行登記。
圖書館短信服務系統,涉及的服務短信的類型如圖2所示。

圖2 服務短信類型Fig.2 Type of SMS service
上行短信是讀者發給系統的,由 CMCC網關接收轉發到系統,系統接收分析后按要求提取信息再反饋給讀者。下行短信由系統按照讀者的定制情況直接發給讀者。另外,短信的發送有 2種情況,一對多是同樣的短信內容發給多個讀者,一對一是對不同的讀者發送不同的短信內容。上行短信的反饋信息都是一對一形式。
目前,Node.js憑借其優秀的性能受到全球各大公司的重視,如 eBay、Microsoft、PayPal、Uber、Yahoo等,國內阿里巴巴、百度、騰訊等也在很多的項目中應用,可見 Node.js的發展已經很成熟,它能快速創建大規模的網絡應用,處理高吞吐量的實時連接。Node.js有 Windows、Linux、macOS、SunOS、AIX等系統平臺版本,因而具有良好的跨平臺可移植性,可以在 Windows上開發,然后部署到 Linux等其他系統上[2]。
短信服務系統的服務器,采用的操作系統是CentOS 6.10版,綜合以往基于 Linux系統的開發經驗,以及 Node.js對 Mysql、Oracle、DB2數據庫系統的強大支持和良好的性能,我們最終采用 Node.js進行短信服務系統的開發工作。
Node.js是通過數據庫訪問模塊實現對數據庫訪問的,訪問不同類型的數據庫需要加載不同的模塊,這些模塊的使用過程包括安裝、連接配置和訪問操作。
在短信服務系統中涉及的數據庫類型有 Mysql、Oracle和 DB2。Node.js訪問數據庫的模塊可以在npmjs.com搜尋,這里有廠商官方提供的以及個人編寫的很多模塊,良莠不齊,具體采用哪個需要甄別。我們根據模塊的使用量和使用效果選擇了 mysql、ibm_db、oracledb這3個模塊。
mysql模塊的安裝比較簡單,只需使用命令 npm install mysql安裝即可。而 oracledb、ibm_db這 2個模塊,首先需要根據操作系統下載并安裝驅動程序,然后再進行編譯和安裝。下面將安裝過程中需要注意的問題進行總結。
2.1.1 ibm_db模塊
選擇 Node.js 8.12版。首先,安裝 gcc和 gccc++(即g++,在CentOS中稱為gcc-c++),安裝后gcc版本如果是 4.7,需要升級到 4.8,再安裝 devtoolset-2-gcc、devtoolset-2-binutils、devtoolset-2-gcc-c++ 3 個軟件包,它們會被安裝在/opt/rh/devtoolset-2/root/中,要注意在/usr/bin中建立它們的軟連接,以便使用。
然后,安裝DB2客戶端程序,在/app文件夾中釋放linuxx64_odbc_cli.tar.gz,再在/etc/profile文件中增加以下環境變量。
export LD_LIBRARY_PATH=/app/clidriver/lib:$LD_LIBRARY_PATH
最后是安裝 ibm_db。使用命令 npm install ibm_db并注意此時在系統環境中不能有IBM_DB_HOME變量定義,否則無法安裝,如果變量已經定義,則用 export n IBM_DB_HOME命令去掉。當安裝過程提示訪問權限問題時,使用下面的命令:
npm install --unsafe-perm=true --allow-root ibm_db
命令執行完成后,進入 node_modules/ibm_db目錄中,首先需要定義變量 export IBM_DB_HOME=/app/clidriver,然后執行以下命令:
node-gyp configure build --IBM_DB_HOME=$IBM_DB_HOME --IS_DOWNLOADED=false -verbose[3]
在編譯過程可能會有警告出現,不用理會,只要執行過程中沒有報錯就說明安裝成功了。
2.1.2 oracledb模塊
首先,安裝 oracle instant client,12.2.0.1.0 版,可到 oracle官網下載 instantclient-basic-linux.x64-12.2.0.1.0.zip文件,解壓縮到指定目錄。
然后,把下面的內容寫入環境變量文件/etc/profile中:
export ORACLE_HOME=/app/instantclient_12_2
export PATH=$ORACLE_HOME:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
export TNS_ADMIN=$ORACLE_HOME/tns
最后,安裝 oracledb 模塊,運行命令npm install oracledb[4],如果出現訪問權限問題,則使用下面的命令安裝:
npm install --unsafe-perm=true --allow-root oracledb
首先,引入模塊并定義數據庫連接參數,再建立數據庫的鏈接,然后執行 sql查詢語句并獲取數據,最后關閉連接。下面是使用mysql模塊獲取預設的短信內容的例子。

下面代碼是執行查詢語句并獲取數據。

其他數據庫訪問模塊的使用方法大同小異,只是一些代碼細節有所不同,如 oracledb中使用connection.execute語句來執行 sql查詢語句獲取數據,具體使用方法還需仔細閱讀相關文檔。
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是再重新建立一個;釋放空閑時間超過最大空閑時間的數據庫連接來避免因為沒有釋放數據庫連接而引起的數據庫連接遺漏。這項技術能明顯提高對數據庫操作的性能[5]。
在 Node.js中可以方便地使用數據庫連接池技術,以oracle為例,在oracledb中連接池的最大連接數poolMax缺省是4,通過代碼可以設置。
var oracledb=require('oracledb');oracledb.pool Max=10;
下面一段代碼是短信服務系統中完整的應用oralcedb連接池的例子。義數據庫連接池的名字


使用數據庫連接池技術,并發執行數量越大時比普通連接方式越有明顯的優勢,程序執行效率高,支持的最大并發執行數也會遠超普通連接。
Node.js的異步處理是其精華所在,可以有效地利用資源,提高系統的性能,更好地改善用戶的體驗,同樣會提高對多種數據庫協同訪問的效率,但也使編程的難度提高了很多。傳統的 Node.js在處理異步問題時,一般采用callback回調的方式,callback回調存在一個很嚴重的金字塔問題——大量的回調函數慢慢向右側屏幕延伸的一種狀態[6]。回調函數嵌套過多,可讀性極差,容易出錯,形成“回調地獄”。
Promise為 Javascript中的改進鋪平了道路。EcmaScript 2017以 async和 await語句的形式,在JavaScript的 Promise之上引入了語法糖。它們允許編寫基于 Promise的代碼,就好像它是同步的,但不會阻塞主線程[7]。
在Node.js版本8中已經支持async和await語法。async函數返回一個Promise對象,當函數執行的時候,一旦遇到 await就會先等待,等到異步操作完成,再接著執行函數體內后面的語句。這樣就將異步的代碼寫成同步的形式,代碼容易理解,可讀性大為提高,減少代碼錯誤的產生,避免了“回調地獄”發生。下段代碼是發送“年檢提醒”訪問數據庫的程序,從中可見一斑。


圖書館短信服務系統從2018年10月上線至今,系統運行穩定,處理速度快。這說明 Node.js應用于多種異構數據庫的協同訪問,效果良好,異步和并發的性能優異、穩定可靠,是一個值得采用和深入研究的方案。
Node.js自身哲學是花最小的硬件成本,追求更高的并發,更高的處理性能[8]。Node.js使用的是JavaScript語言,相對學習成本較低、模塊化的開發模式,可以利用的資源豐富,現在已經形成了完整的資源生態,而且社區發達,許多人把問題都放到社區交流討論,可以幫助縮短開發周期。另外,開發中所用的操作系統、工具、模塊大都是免費的,運行時系統對硬件資源的消耗相對于其他流行語言如 Java要小,這也降低了開發成本。
Node.js經歷了10年的發展歷程,今后一定會更加完善,它的使用范圍有待我們進一步探索。