| 2009 年 10 月 26 日 數據庫系統為用戶(hù)提供了多樣的編程接口,以適用于各種應用需求。本文闡述了 DB2 中靜態(tài) SQL 和動(dòng)態(tài) SQL 的區別和特點(diǎn),給出兩種 SQL 在不同編程接口下的支持情況和典型應用,并通過(guò)實(shí)際案例,向讀者介紹了選擇靜態(tài)或動(dòng)態(tài) SQL 及編程接口的原則。 引言 SQL 語(yǔ)言作為標準的查詢(xún)語(yǔ)言,幾乎被所有的數據庫管理系統 (DBMS) 所支持,并成為國際標準。標準的 SQL 語(yǔ)言一般包括三類(lèi),即 DDL (Data Definition Language, 數據描述語(yǔ)言 ) 、DML (Data Manipulation Language, 數據操縱語(yǔ)言 ) 和 DCL(Data Control Language,數據控制語(yǔ)言 )。通過(guò)這些標準的 SQL 語(yǔ)句,使得各種數據庫能以一種較為統一的方式被訪(fǎng)問(wèn)。 DB2(本文以下專(zhuān)指 DB2 UDB for Linux, Unix 和 Windows 版本)允許用戶(hù)通過(guò)多種編程接口發(fā)送 SQL 語(yǔ)句到數據庫引擎,然后由引擎統一編譯并且運行。SQL 語(yǔ)句從編譯和運行的角度可以分為兩種,靜態(tài) SQL和 動(dòng)態(tài) SQL,這兩種 SQL 在使用方式、運行機制和性能表現等方面各有特點(diǎn) : - 靜態(tài) SQL:靜態(tài) SQL 語(yǔ)句一般用于嵌入式 SQL 應用中,在程序運行前,SQL 語(yǔ)句必須是確定的,例如 SQL 語(yǔ)句中涉及的列名和表名必須是存在的。靜態(tài) SQL 語(yǔ)句的編譯是在應用程序運行前進(jìn)行的,編譯的結果會(huì )存儲在數據庫內部。而后程序運行時(shí),數據庫將直接執行編譯好的 SQL 語(yǔ)句,降低運行時(shí)的開(kāi)銷(xiāo)。
- 動(dòng)態(tài) SQL:動(dòng)態(tài) SQL 語(yǔ)句是在應用程序運行時(shí)被編譯和執行的,例如,使用 DB2 的交互式工具 CLP 訪(fǎng)問(wèn)數據庫時(shí),用戶(hù)輸入的 SQL 語(yǔ)句是不確定的,因此 SQL 語(yǔ)句只能被動(dòng)態(tài)地編譯。動(dòng)態(tài) SQL 的應用較多,常見(jiàn)的 CLI 和 JDBC 應用程序都使用動(dòng)態(tài) SQL。
表 1列舉了靜態(tài) SQL 和動(dòng)態(tài) SQL 的比較結果。 表 1. 靜態(tài) SQL 和動(dòng)態(tài) SQL 的比較 | 靜態(tài) SQL | 動(dòng)態(tài) SQL | | SQL 語(yǔ)句直接嵌入到宿主編程語(yǔ)言,程序需要預編譯處理這些嵌入的 SQL 語(yǔ)句 | SQL 語(yǔ)句一般作為宿主語(yǔ)言的變量出現。嵌入式動(dòng)態(tài) SQL 應用需要預編譯,非嵌入式 SQL 應用則無(wú)需預編譯 | | SQL 語(yǔ)句在程序被編譯時(shí)已知,涉及的數據庫對象已存在 | SQL 語(yǔ)句在程序被編譯時(shí)未知,涉及的數據庫對象可以是運行時(shí)才創(chuàng )建的 | | SQL 語(yǔ)句在程序運行前被編譯 | SQL 語(yǔ)句在程序運行時(shí)被編譯 | | SQL 語(yǔ)句的編譯結果在 DB2 的目錄 (catalog) 中持久化保存 | SQL 語(yǔ)句的編譯結果緩存在數據庫的內存里 | | 運行時(shí)僅讀取目錄 (catalog) | 運行時(shí)編譯 SQL 語(yǔ)句需對目錄 (catalog) 加鎖 | | SQL 語(yǔ)句的優(yōu)化是根據編譯時(shí)的數據庫統計信息進(jìn)行的,不能完全反映運行時(shí)的情況 | SQL 語(yǔ)句的優(yōu)化是根運行時(shí)的數據庫統計信息進(jìn)行的 | | 對 SQL 語(yǔ)句所訪(fǎng)問(wèn)的數據對象的權限檢查是在綁定時(shí)進(jìn)行的 | 對 SQL 語(yǔ)句所訪(fǎng)問(wèn)的數據對象的權限檢查是在運行時(shí)進(jìn)行的 | | 權限控制的粒度是包(package,一組 SQL 語(yǔ)句的編譯結果),用戶(hù)僅需要訪(fǎng)問(wèn)包的權限 | 權限控制的粒度是 SQL 語(yǔ)句,用戶(hù)需要具有訪(fǎng)問(wèn) SQL 語(yǔ)句中每個(gè)數據對象的權限 | | 如果 SQL 語(yǔ)句中的對象被修改,如 DDL 執行,整個(gè)包都需要重新綁定 | 當 SQL 語(yǔ)句中的對象被修改時(shí),僅執行過(guò)的語(yǔ)句在下次運行時(shí)需要重新編譯 | 根據編程方法的不同,DB2 的應用程序開(kāi)還可以分為嵌入式 SQL 編程和非嵌入式編程 : - 嵌入式 SQL 編程將 SQL 語(yǔ)句嵌入到宿主語(yǔ)言 (host) 的程序中,例如 C/C++ 程序。因為宿主語(yǔ)言不識別 SQL 語(yǔ)句,先要對程序進(jìn)行預編譯,把 SQL 語(yǔ)句轉變?yōu)閷?DB2 服務(wù)的調用,并重寫(xiě)源代碼,最后再使用宿主語(yǔ)言的編譯器對應用程序進(jìn)行編譯。嵌入式 SQL 都需要被綁定到特定的數據庫中,可分為嵌入式靜態(tài) SQL 和嵌入式動(dòng)態(tài) SQL。
- 非嵌入式應用程序不需要預編譯,且方法較多,如 CLI、JDBC、ODBC、ADO.NET 等等,這些方法中都使用動(dòng)態(tài) SQL。表 2列舉了常見(jiàn)的 DB2 編程接口。
表 2. DB2 的編程接口一覽 | 編程接口 | 靜態(tài) / 動(dòng)態(tài) | 是否為嵌入式 | | 嵌入式 SQL | 靜態(tài)和動(dòng)態(tài) | 是 | | DB2 CLI | 動(dòng)態(tài) | 否 | | SQLJ | 靜態(tài) | 是 | | JDBC | 動(dòng)態(tài) | 否 | | ADO.NET,OLE DB | 動(dòng)態(tài) | 否 | | Perl DBI | 動(dòng)態(tài) | 否 | | PDO(PHP 數據對象 ) | 動(dòng)態(tài) | 否 | 在下面的幾個(gè)章節中,我們將陸續從使用角度上描述靜態(tài)和動(dòng)態(tài) SQL 在各種編程接口中的應用,并運用一些實(shí)例來(lái)介紹在具體的場(chǎng)景中如何選擇。 靜態(tài) SQL 應用 嵌入式靜態(tài) SQL 無(wú)論是嵌入式靜態(tài) SQL 還是嵌入式動(dòng)態(tài) SQL,都需要先進(jìn)行預編譯,并綁定到特定的數據庫。DB2 的嵌入式 SQL 應用程序支持以下幾種語(yǔ)言:C,C++,COBOL,FORTRAN 和 REXX?。 對嵌入式靜態(tài) SQL 而言,只能使用編譯時(shí)確定的 SQL 語(yǔ)句和訪(fǎng)問(wèn)編譯時(shí)已經(jīng)存在的數據庫對象。清單 1是一個(gè)查詢(xún)表的例子,使用 C 語(yǔ)言 : 清單 1. 嵌入式靜態(tài) SQL 的 C 語(yǔ)言片斷 //test.sqc EXEC SQL INCLUDE SQLCA; EXEC SQL BEGIN DECLARE SECTION; sqlint32 t_seq = 0; char t_name[64]={0}; EXEC SQL END DECLARE SECTION; ... t_seq = 5; EXEC SQL SELECT c_name INTO :t_name FROM test_tbl WHERE seq=:t_seq; printf("c_name = %s \n", t_name); | 使用下面的命令,對上述代碼進(jìn)行預編譯和編譯: 清單 2. 嵌入式靜態(tài) SQL 的編譯命令 # 需要先連接數據庫 db2 connect to TESTDB # 使用 PREP 命令對 sqc 源文件進(jìn)行預編譯,這將生成 test.c 源文件 db2 PREP test.sqc # 使用 C 編譯器對 test.c 進(jìn)行編譯 xlC -q64 -I$DB2PATH/include -g -L$DB2PATH/lib -ldb2 -o test test.c | SQLJ SQLJ 是應用于靜態(tài) SQL 的 Java 編程接口。使用 SQLJ 編寫(xiě)應用程序和使用其他的語(yǔ)言接口相似,一個(gè)典型的 SQLJ 應用程序主要包括以下幾個(gè)方面: - 載入包含 SQLJ 和 JDBC 的 Java 包。
- 定義收發(fā)數據的載體變量。
- 連接至數據庫,運行相應的 SQL 語(yǔ)句并且正確處理錯誤情況,最后從數據庫斷開(kāi)。
清單 3是 SQLJ 中執行 SELECT 語(yǔ)句的代碼片斷。 清單 3. 簡(jiǎn)單的 SQLJ 程序片斷 // 載入相關(guān)包 import sqlj.runtime.*; import java.sql.*; // 連接至數據庫 Connection con0 = DriverManager.getConnection(url); // 執行相關(guān)的 SQL 語(yǔ)句 #sql [ctx] iter = {SELECT NAME FROM EMP}; // 得到結果 while (iter.next()) { System.out.println(iter.LASTNAME()); } | 在 SQLJ 應用程序中,可以使用 ExecutionContext 類(lèi)去控制和監控 SQL 語(yǔ)句的執行,如 清單 4所示。 清單 4. 在 SQLJ 使用 ExecutionContext // 分配存儲執行上下文的變量 ExecutionContext exeCtx=new ExecutionContext(); // 關(guān)聯(lián)變量和要執行的語(yǔ)句 #sql [connCtx, exeCtx] {DELETE FROM EMP WHERE SALARY > 10000}; // 獲取結果 System.out.println("Deleted " + exeCtx.getUpdateCount() + " rows"); | 動(dòng)態(tài) SQL 應用 嵌入式動(dòng)態(tài) SQL 與嵌入式靜態(tài) SQL 相同,嵌入式動(dòng)態(tài) SQL 也需要預編譯。不同的是,嵌入式動(dòng)態(tài) SQL 將 SQL 語(yǔ)句存放在宿主語(yǔ)言的字符型變量中,這樣的 SQL 語(yǔ)句在預編譯時(shí)是不被處理的,而是被當作主機變量對待,直到程序運行時(shí)才被編譯執行。 得益于動(dòng)態(tài) SQL 的優(yōu)點(diǎn),嵌入式動(dòng)態(tài) SQL 可以處理運行時(shí)才確定的 SQL 語(yǔ)句,例如由程序運行時(shí)拼接的 SQL 語(yǔ)句。為了處理返回結果未知的 SELECT 語(yǔ)句,嵌入式動(dòng)態(tài) SQL 使用 SQLDA(SQL descriptor area) 結構和 DESCRIBE 語(yǔ)句獲取結果集的結構和屬性。SQLDA 結構如 圖 1所示。HEADER 描述整個(gè)結果集的信息,而每個(gè) SQLVAR 結構描述結果集中一個(gè)字段的信息。 圖 1. SQLDA 結構
清單 5展示了如何使用 SQLDA 結構和 DESCRIBE 語(yǔ)句處理 SELECT 語(yǔ)句。 清單 5. 使用 SQLDA 結構和 DESCRIBE 語(yǔ)句的偽代碼 //test1.sqc // 聲明兩個(gè) SQLDA 指針,minsqlda 將是一個(gè)最小的 SQLDA 結構,用于 PREPARE 語(yǔ)句, // 此時(shí)結果集的字段數量未知,所以只需一個(gè)最小的 SQLDA,即包含 HEADER 和一個(gè) SQLVAR struct sqlda * minsqlda = new sqlda; struct sqlda * fulsqlda = NULL; strcpy(hostVarStmt, "SELECT name FROM TEST_TBL"); // PREPARE 將填寫(xiě) minsqlda 的 header,sqldabc 為 SQLDA 總長(cháng)度,sqln 為 SQLVAR 數量,即字段數量 EXEC SQL PREPARE STMT INTO :*minsqlda FROM :hostVarStmt; // 根據從 minsqlda 中獲取的長(cháng)度,分配完整的 SQLDA 結構 fulsqlda,其中將包括合適數量的 SQLVAR 結構 fulsqlda = (struct sqlda *)malloc(SQLDASIZE(minsqlda->sqln)); // 使用 DESCRIBE 語(yǔ)句,獲取結果集中每個(gè)字段的描述信息,包括各字段的類(lèi)型 (sqltype) 和長(cháng)度 (sqllen) EXEC SQL DESCRIBE STMT INTO :fulsqlda; Loop { // 根據每個(gè)字段的長(cháng)度,分配內存,將地址存儲在對應 SQLVAR 的 sqldata 中 } // 聲明游標 EXEC SQL DECLARE c1 CURSOR FOR STMT; EXEC SQL OPEN c1; // 讀取記錄,記錄中每個(gè)字段的內容將寫(xiě)入 fulsqlda 中對應 SQLVAR 結構的 sqldata 指向的內存 EXEC SQL FETCH c1 USING DESCRIPTOR :*fulsqlda; // 循環(huán)讀取所有記錄 while (sqlca.sqlcode != 100) { EXEC SQL FETCH c1 USING DESCRIPTOR :*fulsqlda; } EXEC SQL CLOSE c1; | DB2 CLI DB2 CLI(Call Level Interface)基于微軟的 ODBC(Open Database Connectivity)標準,同時(shí)也增加了 DB2 特有的功能。它允許開(kāi)發(fā)人員使用 C/C++ 語(yǔ)言訪(fǎng)問(wèn) DB2 并通過(guò)函數調用將動(dòng)態(tài) SQL 語(yǔ)句傳遞給 DB2。DB2 CLI 一方面在 ODBC 的環(huán)境中作為 ODBC 驅動(dòng)被 ODBC 管理器加載,另一方面,應用程序也可以直接使用 DB2 CLI API,此時(shí)具有更好的性能。清單 6展示了 CLI 如何執行一個(gè) DELETE 語(yǔ)句。 清單 6. CLI 應用程序片斷 /* SQL statements to be executed */ SQLCHAR * stmt1 = (SQLCHAR *)"delete from test1 where col1 = 5"; /* directly execute statement 1 */ cliRC = SQLExecDirect(hstmt, stmt1, SQL_NTS); | 對一個(gè)返回結果未知的 SELECT 查詢(xún)語(yǔ)句,需要使用相關(guān)的 CLI API 函數動(dòng)態(tài)地獲取對結果集的描述,并取回數據。圖 2展示了這個(gè)處理過(guò)程。 圖 2. DB2 CLI 應用程序處理 SELECT 語(yǔ)句流程 與嵌入式動(dòng)態(tài) SQL 應用相比,CLI 程序的靈活性更強。表 3列舉了 CLI 應用程序和嵌入式動(dòng)態(tài) SQL 應用程序的比較。 表 3. CLI 應用程序和嵌入式動(dòng)態(tài) SQL 應用程序的比較 | CLI | 嵌入式動(dòng)態(tài) SQL | | DB2 CLI 應用程序使用 API 函數發(fā)送 SQL 語(yǔ)句,應用程序的編譯、連接和運行獨立于特定數據庫,即無(wú)需預編譯,也不需要綁定到某個(gè)數據庫實(shí)例。 | 嵌入式動(dòng)態(tài) SQL 應用程序需要預編譯,并且需要綁定到特定的數據庫實(shí)例。 | | CLI 提供的滾動(dòng)游標(scroll cursor)支持前、后向移動(dòng)一行或者多行記錄,而移動(dòng)的起點(diǎn)可以是第一行、最后一行或者之前存儲的位置。 | 只支持順序前向讀取游標,并使用 FETCH 語(yǔ)句取得記錄。 | | 可以獲取存儲過(guò)程調用返回的結果集。并支持多種 DB2 服務(wù)器。 | 可以獲取存儲過(guò)程的輸出型或輸入 - 輸出型參數的值,但不能獲取存儲過(guò)程返回的結果集。 | | 只支持 C/C++ 語(yǔ)言。 | 支持 C/C++, FORTRAN、COBOL 和 Java(SQLJ)。 | | 使用 CLI API 函數 SQLDescribeCol()、SQLAttribute() 描述未知 SQL 語(yǔ)句結果集的信息,包括結果集字段長(cháng)度、類(lèi)型、精度等信息。 | 使用 SQLDA 結構和 DESCRIBE 語(yǔ)句獲取未知 SQL 語(yǔ)句結果集的字段列表,包括類(lèi)型、長(cháng)度等信息。 | JDBC JDBC 是 Java 編程語(yǔ)言訪(fǎng)問(wèn)關(guān)系型數據庫的工業(yè)標準,類(lèi)似于 ODBC,為訪(fǎng)問(wèn)基于 SQL 的數據庫提供了一組調用級的 API。在 JDBC 規范中,存在 4 種類(lèi)型的 JDBC 驅動(dòng),DB2 LUW V9.7 中支持 Type 2 和 Type 4 兩種類(lèi)型。更多關(guān)于 JDBC 的信息可參考 DB2 UDB for Linux, UNIX 和 Windows 中的 Java 開(kāi)發(fā)概述(參見(jiàn) 參考資源部分)。 JDBC 以 Java 包的形式提供了一組接口和類(lèi),用來(lái)連接數據庫和執行 SQL 語(yǔ)句,這里的 SQL 語(yǔ)句也是動(dòng)態(tài) SQL,無(wú)須預編譯和數據庫綁定。清單 7所示為 JDBC 程序片斷。 清單 7. JDBC 應用程序片斷 try{ stmt = con.prepareCall("select * from table1"); stmt.execute(); rs = stmt.getResultSet(); while (rs!=null && rs.next()) { System.out.println("output: = " + rs.getInt(1)); } }catch(SQLException sqle) { System.out.println("Error, SQLCODE = " + sqle.getSQLState()); con.rollback(); } | 除了編程語(yǔ)言和運行基礎架構的不同,JDBC 應用和 CLI 應用具有很多相似的特性,例如它們都支持后向游標,分布式事務(wù)等。 ADO.NET 和 OLE DB ADO.NET 是 Microsoft .NET Framework 基礎類(lèi)庫的一部分,提供了訪(fǎng)問(wèn)關(guān)系型數據庫系統和其他數據源的能力。ADO.NET 主要包括兩個(gè)部分:DataSet 和 DataProvider。使用 ADO.NET,有三種 DataProvider 可以用來(lái)訪(fǎng)問(wèn) DB2: - OLE DB .NET Data Provider 和 ODBC .NET Data Provider 是兩種橋接式 provider,它們將 ADO.NET 請求轉換為對 IBM OLE DB Provider 或 IBM ODBC Driver 的請求。
- DB2 .NET Data Provider 是訪(fǎng)問(wèn) DB2 時(shí)推薦使用的 .NET provider,由于沒(méi)有額外的 OLE DB 或 ODBC 層,它具有更好的性能。
OLE DB 是一種較早出現的數據訪(fǎng)問(wèn)模型,它基于 Microsoft? 的 COM 技術(shù),提供了訪(fǎng)問(wèn)不同信息源的統一方法。OLE DB 定義了 OLE DB 消費者和提供者,OLE DB 消費者可以通過(guò) IBM OLE DB Provider for DB2 訪(fǎng)問(wèn) DB2 中的數據。使用 OLE DB 訪(fǎng)問(wèn) DB2 的應用程序可能包括 Microsoft? Visual Studio C++ 應用,Microsoft Visual Basic 應用,ATL 應用等。 其他應用程序開(kāi)發(fā)接口 Perl 程序員可以使用 Perl 數據庫接口 DBI 來(lái)訪(fǎng)問(wèn) DB2。IBM 提供的 DBI 驅動(dòng)為 IBM?DB2?Database Driver for Perl DBI (the DBD::DB2 driver)。Perl DBI 同樣使用動(dòng)態(tài) SQL,而且 Perl DBI 的接口與 CLI 和 JDBC 很相似,易于使用。 PHP 在 Web 應用開(kāi)發(fā)領(lǐng)域一直占據很大份額,IBM 提供了下面兩種 PHP 擴展以訪(fǎng)問(wèn) DB2 數據庫: - ibm_db2,是一種過(guò)程化的應用編程接口,與 PHP 應用一起編譯,提供一系列的 PHP 函數來(lái)訪(fǎng)問(wèn)數據庫。
- pdo_ibm,是 IBM 提供的 PHP Data Objects (PDO) 驅動(dòng)。
此外,IBM 對 Python,Ruby on Rails 等編程語(yǔ)言都提供了相應的 DB2 訪(fǎng)問(wèn)支持。這些開(kāi)發(fā)接口同樣都使用動(dòng)態(tài) SQL。 應用場(chǎng)景以及如何選擇 本節將結合幾個(gè)應用場(chǎng)景來(lái)介紹如何選擇 DB2 編程接口以及靜態(tài) / 動(dòng)態(tài) SQL。 場(chǎng)景 1 銀行中賬目統計系統比較穩定,一般運行在一個(gè)特定的數據庫中,其目的是整合業(yè)務(wù)數據庫上數據,并通過(guò)分析數據得到一些相關(guān)的統計信息。這樣的系統具有以下一些特點(diǎn) : - 穩定,系統邏輯不會(huì )有什么變化,訪(fǎng)問(wèn)固定的數據庫以及表。
- 定時(shí)運行,賬目統計信息通常需要在一段時(shí)間內進(jìn)行整合。
- 數據量比較大,對性能要求較高。
針對這些特點(diǎn),建議使用主要由靜態(tài) SQL 語(yǔ)句組成的應用程序,這樣該系統在建立的時(shí)候會(huì )被編譯,然后相關(guān)的編譯信息會(huì )被存儲到數據庫里,在以后的運行過(guò)程中避免重復編譯,同時(shí),這種應用由于結構簡(jiǎn)單使得其很容易維護。當然,由于系統的數據變化較快,而且數據量很大,所以建議定時(shí)重新編譯程序,使得數據庫對每條 SQL 語(yǔ)句可以選擇最優(yōu)的運行方式。 場(chǎng)景 2 考慮電信運營(yíng)商對用戶(hù)話(huà)單的計費場(chǎng)景,圖 3顯示了一個(gè)電信運行系統結構圖。業(yè)務(wù)系統產(chǎn)生的各種話(huà)單會(huì )集中存放在一個(gè)關(guān)系型數據庫中,該數據庫可能位于大規模的高可靠性服務(wù)器。而計費程序則往往作為一個(gè)單獨的應用部署在其他規模較小的 UNIX 服務(wù)器上,并作為守護程序或者批處理程序運行。另外,很多業(yè)務(wù)規則例如計費標準可能存放在單獨得小型數據庫系統中。 圖 3. 電信運營(yíng)系統結構示意圖 計費程序的工作主要包括:從話(huà)單數據庫讀新話(huà)單,從業(yè)務(wù)配置數據庫讀取計費標準,計算話(huà)單的費用和優(yōu)惠,將計費完畢的話(huà)單寫(xiě)回話(huà)單數據庫。 由于計費標準的選擇經(jīng)常和日期等變化的信息相關(guān),程序中會(huì )存在一些不固定的 SQL 語(yǔ)句,因此靜態(tài) SQL 應用并不適用。另外,除了訪(fǎng)問(wèn)結構穩定的話(huà)單數據庫,計費程序也需要訪(fǎng)問(wèn)一些變化概率較大的小型數據庫,例如計費標準可能會(huì )因為運營(yíng)商營(yíng)銷(xiāo)策略的調整而發(fā)生變化。如果使用嵌入式 SQL,就必須將應用程序和數據庫進(jìn)行綁定,這將失去靈活性。最后,為了快速對大量的話(huà)單進(jìn)行計費,計費程序對性能也有較高要求,所以 CLI 應用程序比 JDBC 應用更適合計費程序。 場(chǎng)景 3 在基于 BS 結構的電子商務(wù)應用中,瀏覽器、應用服務(wù)器(包括 Web 服務(wù)器)和數據庫構成了系統的三個(gè)要素。數據庫為電子商務(wù)提供了事務(wù)管理、數據持久化、安全認證、聯(lián)機備份等各方面的支持,是電子商務(wù)系統中的關(guān)鍵部分。圖 4顯示了一個(gè)簡(jiǎn)單的電子商務(wù)系統結構示意圖。 圖 4. 簡(jiǎn)單的電子商務(wù)系統結構示意圖 在電子商務(wù)系統的實(shí)現中,數據庫訪(fǎng)問(wèn)接口的選擇很大程度上依賴(lài)于所選擇的應用集成方案。例如傳統的 J2EE 應用中使用 JDBC 實(shí)現數據庫訪(fǎng)問(wèn)。又如開(kāi)源框架 STRUTS,SPRING 和 HIBERNATE,由 HIBERNATE 完成對 JDBC 的封裝,提供對數據庫的訪(fǎng)問(wèn)能力?;?PHP 開(kāi)發(fā)的 Web 應用程序同樣非常流行,如果選擇 PHP 作為開(kāi)發(fā)語(yǔ)言,那么使用 PDO(PHP Data Objects)和 IBM 提供的 pdo_ibm 驅動(dòng)即可訪(fǎng)問(wèn) DB2 數據庫。對基于 .Net 框架開(kāi)發(fā)的 Web 應用而言,ADO.NET 則是最合適的數據庫訪(fǎng)問(wèn)接口。 靜態(tài) SQL 和動(dòng)態(tài) SQL 的選擇原則 在以下情況下,適合選用靜態(tài) SQL: - 程序需要處理 SQL 語(yǔ)句頻率高,壓力較大
- SQL 語(yǔ)句較為簡(jiǎn)單且已知不變
- SQL 語(yǔ)句訪(fǎng)問(wèn)的數據庫對象變化很少
- 程序使用的 SQL 語(yǔ)句可以統一認證權限
- 同一條 SQL 語(yǔ)句重復執行的次數很少
- 很少運行 RUNSTATS 更新統計信息
在以下情況下,更適合選用動(dòng)態(tài) SQL: - SQL 語(yǔ)句在應用程序執行時(shí)才生成
- SQL 語(yǔ)句訪(fǎng)問(wèn)的對象在程序運行前不存在
- 希望 SQL 語(yǔ)句根據運行時(shí)的數據庫統計信息進(jìn)行最好的優(yōu)化
- 在程序運行中可能更改 SQL 語(yǔ)句的編譯環(huán)境,如配置參數和特殊寄存器的值
- 程序運行時(shí),同時(shí)有較多 DDL 語(yǔ)句執行
- 選用特定的應用程序框架,例如場(chǎng)景 3 中的電子商務(wù)案例
當然,所有的原則都是經(jīng)驗性的,真正的選擇還取決于應用的實(shí)際情況。在時(shí)間允許的情況下,對各種選擇進(jìn)行比較測試也是可以考慮的方法。 |