級(jí)別: 初級(jí)
Connie Tsui, DB2 解決方案集成團(tuán)隊(duì), IBM 多倫多實(shí)驗(yàn)室
2003 年 2 月 01 日
了解為什么 SQLJ 是注重安全性、性能和簡(jiǎn)單性的開(kāi)發(fā)人員所選擇的語(yǔ)言。其中還包含了代碼樣本。
簡(jiǎn)介
使用 Java? 訪問(wèn)關(guān)系數(shù)據(jù)的標(biāo)準(zhǔn)方法有兩種:SQLJ 和 JDBC?。對(duì)于 IBM® DB2® Universal Database?(UDB)應(yīng)用程序,為什么應(yīng)該考慮 SQLJ 呢?這是因?yàn)楫?dāng)應(yīng)用程序員要考慮安全性、性能和簡(jiǎn)單性時(shí),往往會(huì)選擇 SQLJ 這樣的語(yǔ)言。本文向您介紹了有關(guān) SQLJ 的一些背景,討論了相對(duì)于 JDBC,SQLJ 所具有的優(yōu)勢(shì),還特別指出了 DB2 UDB V8.1 所提供的一些新增和改進(jìn)的 SQLJ 特性。
SQLJ 的背景
1997 年 4 月,一個(gè)由數(shù)據(jù)庫(kù)供應(yīng)商組成的非正式和開(kāi)放小組開(kāi)始定期開(kāi)會(huì),交流有關(guān)如何在 Java 編程語(yǔ)言中使用靜態(tài) SQL 語(yǔ)句和構(gòu)造的想法。主要參與者包括 IBM、Oracle、Compaq、Informix®、Sybase、Cloudscape 和 Sun Microsystems。該小組把他們正制定的規(guī)范命名為 JSQL。但他們發(fā)現(xiàn)術(shù)語(yǔ) JSQL 是一個(gè)注冊(cè)商標(biāo),因此就將 JSQL 重命名為 SQLJ。1997 年 12 月,Oracle 向其它成員提供了一個(gè) Java 中嵌入式 SQL 的參考實(shí)現(xiàn)。這個(gè)參考實(shí)現(xiàn)可以在任何支持 JDK 1.1 的平臺(tái)上運(yùn)行,并且它與供應(yīng)商無(wú)關(guān)。1998 年 12 月,完成了 Java 中嵌入式 SQL 規(guī)范的整個(gè)開(kāi)發(fā)工作,并被接納為 ANSI 標(biāo)準(zhǔn) Database Language - SQL, Part 10 Object Language Bindings (SQL/OLB)ANSI x3.135.10-1998。這個(gè)規(guī)范一般稱(chēng)為 SQLJ 規(guī)范的第 0 部分。現(xiàn)在它被稱(chēng)為 SQL/OLB(對(duì)象語(yǔ)言綁定,Object Language Binding)。
SQLJ 規(guī)范目前由兩部分組成:
- SQL/OLB:Java 中的嵌入式 SQL
這部分標(biāo)準(zhǔn)規(guī)定了在 Java 方法中嵌入 SQL 的語(yǔ)法和語(yǔ)義,還規(guī)定了一些機(jī)制來(lái)確保生成的 SQLJ 應(yīng)用程序的二進(jìn)制可移植性。這正是本文要闡述的主題。
- SQL/JRT:使用 Java 編程語(yǔ)言的 SQL 例程和類(lèi)型
這部分標(biāo)準(zhǔn)包含以下內(nèi)容:
- 將 Java 靜態(tài)方法作為 SQL 存儲(chǔ)過(guò)程和用戶(hù)定義的函數(shù)來(lái)調(diào)用的規(guī)范。它定義了 SQL 擴(kuò)展,用于在 SQL 系統(tǒng)中安裝 Java 類(lèi),在 SQL 中以 SQL 函數(shù)和存儲(chǔ)過(guò)程方式調(diào)用 Java 類(lèi)的靜態(tài)方法,獲取指定的參數(shù)輸出值以及返回 SQL 結(jié)果集。
- 將 Java 類(lèi)用作 SQL 用戶(hù)定義的數(shù)據(jù)類(lèi)型的規(guī)范。它定義了 SQL 擴(kuò)展,用于將 Java 類(lèi)用作 SQL 中的數(shù)據(jù)類(lèi)型。
術(shù)語(yǔ):當(dāng)我們?cè)诒疚钠溆嗖糠质褂眯g(shù)語(yǔ) SQLJ 時(shí),僅指 SQL/OLB。
SQLJ 編程環(huán)境
SQLJ 環(huán)境由兩個(gè)階段組成:開(kāi)發(fā)和運(yùn)行時(shí)。本節(jié)向您介紹每個(gè)階段所涉及到的組件以及各組件間的關(guān)系。
開(kāi)發(fā) SQLJ 應(yīng)用程序
使用 SQLJ 開(kāi)發(fā)應(yīng)用程序需要三個(gè)組件:轉(zhuǎn)換程序、概要文件定制程序和概要文件綁定程序。有三個(gè)實(shí)用程序提供了支持這三個(gè)組件的功能,它們分別是: sqlj、db2sqljcustomize和 db2sqljbind。這里對(duì) 圖 1中演示的過(guò)程作一個(gè)概述:
- 首先,調(diào)用 SQLJ 轉(zhuǎn)換程序(sqlj)以讀取 SQLJ 源文件并檢查該程序中 SQLJ 語(yǔ)法的正確性。轉(zhuǎn)換程序生成一個(gè) Java 源文件,可能不生成 SQLJ 概要文件或生成多個(gè) SQLJ 概要文件,并且如果所生成的 Java 源文件中沒(méi)有錯(cuò)誤,那么它還可以選擇將該源文件編譯成字節(jié)碼(缺省情況)。生成的 Java 源文件將嵌入式 SQL 替代為對(duì)執(zhí)行 SQL 操作的 SQLJ 運(yùn)行時(shí)的調(diào)用。
- 接著,調(diào)用 SQLJ 概要文件定制程序(db2sqljcustomize)來(lái)為生成的序列化概要文件創(chuàng)建 DB2 定制。該定制程序可以選擇(缺省情況下) 聯(lián)機(jī)檢查能夠動(dòng)態(tài)編譯的 SQL 語(yǔ)句。聯(lián)機(jī)檢查執(zhí)行語(yǔ)法、語(yǔ)義和模式驗(yàn)證。也可以選擇(缺省情況下)調(diào)用 SQLJ 概要文件綁定程序以綁定 DB2 包。
- 如果選擇在概要文件定制期間不執(zhí)行自動(dòng)綁定,那么可以單獨(dú)調(diào)用 SQLJ 概要文件綁定程序(db2sqljbind),以將先前定制的 SQLJ 概要文件綁定到數(shù)據(jù)庫(kù)。
- 不管概要文件是否被定制,要查看其內(nèi)容,可以使用 SQLJ 概要文件打印程序(db2sqljprint)以文本格式打印出概要文件的內(nèi)容。
圖 1. SQLJ 開(kāi)發(fā)環(huán)境
執(zhí)行 SQLJ 應(yīng)用程序
為訪問(wèn)數(shù)據(jù)庫(kù),SQLJ 運(yùn)行時(shí)要依靠 JDBC 驅(qū)動(dòng)程序來(lái)獲取數(shù)據(jù)庫(kù)連接。未定制的 SQLJ 應(yīng)用程序可以與任何 JDBC 2.0 驅(qū)動(dòng)程序一起運(yùn)行。在開(kāi)發(fā)期間,為了測(cè)試,只需運(yùn)行未定制應(yīng)用程序。要運(yùn)行定制的 SQLJ 應(yīng)用程序,可以使用 V8 基于 CLI 的 JDBC 類(lèi)型 2 驅(qū)動(dòng)程序 - 通用 JDBC 驅(qū)動(dòng)程序(類(lèi)型 2 或類(lèi)型 4)來(lái)建立數(shù)據(jù)庫(kù)連接。本節(jié)中,我們只描述用于定制的 SQLJ 應(yīng)用程序的運(yùn)行時(shí)環(huán)境。
當(dāng)您運(yùn)行 SQLJ 應(yīng)用程序時(shí),SQLJ 運(yùn)行時(shí)從定制的概要文件中讀取有關(guān) SQL 操作的信息,并執(zhí)行與存儲(chǔ)在定制中的包關(guān)鍵信息(包名、包一致性標(biāo)記和集合名)相符的 DB2 包中的語(yǔ)句。
圖 2. SQLJ 運(yùn)行時(shí)環(huán)境
SQLJ 相對(duì)于 JDBC 的優(yōu)勢(shì)
SQLJ 規(guī)范和 JDBC 規(guī)范都描述了如何使用 Java 來(lái)訪問(wèn)關(guān)系數(shù)據(jù)庫(kù)。本節(jié)從以下幾個(gè)方面討論它們之間的差異:
表 1匯總了我們?cè)诒竟?jié)中所描述的 SQLJ 和 JDBC 之間的差異。
標(biāo)準(zhǔn)和 SQL 規(guī)范級(jí)別
SQLJ 是 ISO/IEC 9075-10:2000 Information technology -- Database languages -- SQL -- Part 10: Object Language Bindings (SQL/OLB)的實(shí)現(xiàn)。SQLJ 不屬于 J2EE 平臺(tái)。
JDBC 是 J2SE 1.4 和 J2EE 1.4 平臺(tái)規(guī)范的一個(gè)必不可少的組件。它自 Java 軟件開(kāi)發(fā)工具箱(Java Software Development Kit,JDK)V1.1 之后已成為其核心部件。它包含在 java.sql 包中。JDBC 驅(qū)動(dòng)程序必須至少支持 Entry SQL-92 語(yǔ)句,在該規(guī)范中還定義了一些擴(kuò)展。
安全性
SQLJ 中實(shí)現(xiàn)的安全性權(quán)限模型是用戶(hù)考慮使用 SQLJ 的一個(gè)主要原因。使用靜態(tài) SQL,安全性特權(quán)就被指派給了包創(chuàng)建者,并被存儲(chǔ)在 DB2 包中。
使用定制的 DB2 SQLJ,靜態(tài)地執(zhí)行 SQL;因此使用包所有者的特權(quán)來(lái)執(zhí)行 SQL 語(yǔ)句。任何運(yùn)行 SQLJ 應(yīng)用程序的其他用戶(hù)都必須被授予具有該包的 EXECUTE 特權(quán)。即,被授權(quán)可以運(yùn)行程序的用戶(hù)未必有權(quán)對(duì)該程序所查詢(xún)或正在修改的同一表或視圖執(zhí)行 SELECT、UPDATE、DELETE 或 INSERT 操作,除非顯式地授予該用戶(hù)相應(yīng)的特權(quán)。
擁有連接到數(shù)據(jù)庫(kù)并執(zhí)行 JDBC 應(yīng)用程序特權(quán)的人可以執(zhí)行這些應(yīng)用程序中的 SQL 語(yǔ)句。因此,用戶(hù)必須獲得訪問(wèn)表的特權(quán)。
性能
SQLJ 允許在 Java 程序中嵌入 SQL 語(yǔ)句,這類(lèi)似于 SQL-92 允許 SQL 語(yǔ)句嵌入到 C、COBOL、FORTRAN 以及其它編程語(yǔ)言中的方式。但是,根據(jù) SQLJ 概要文件是否被定制,可以決定 SQLJ 應(yīng)用程序是動(dòng)態(tài)還是靜態(tài)地運(yùn)行。當(dāng)將包存儲(chǔ)在 DB2 數(shù)據(jù)庫(kù)中時(shí),就會(huì)預(yù)編譯 SQLJ 應(yīng)用程序并優(yōu)化 SQL 語(yǔ)句的路徑長(zhǎng)度。靜態(tài)執(zhí)行的 SQLJ 應(yīng)用程序的性能會(huì)優(yōu)于 JDBC 的性能。
如果想利用靜態(tài)執(zhí)行(我們建議這樣做),必須使用 SQLJ 概要文件定制程序來(lái)定制概要文件。
JDBC 提供了 SQL 語(yǔ)句的動(dòng)態(tài)執(zhí)行。如果這些語(yǔ)句中存在語(yǔ)法或語(yǔ)義錯(cuò)誤,那么在該應(yīng)用程序運(yùn)行時(shí)任何此類(lèi)異常都會(huì)產(chǎn)生。
使用 DB2 UDB 監(jiān)視器可以驗(yàn)證靜態(tài)或動(dòng)態(tài)的 SQL 語(yǔ)句處理。監(jiān)控方法有兩種:快照監(jiān)控和事件監(jiān)控。快照監(jiān)視器提供有關(guān)數(shù)據(jù)庫(kù)在某個(gè)特定時(shí)間點(diǎn)的活動(dòng)信息。事件監(jiān)視器記錄了 DB2 UDB 事件發(fā)生的特定位置。下面的 清單 1 摘自從 JDBC 程序生成的事件監(jiān)視器的樣本輸出。“Type: Dynamic”告訴您動(dòng)態(tài)執(zhí)行了 SELECT job FROM staff WHERE name = ? 語(yǔ)句。
清單 1. 從 JDBC 程序生成的事件監(jiān)視器的樣本輸出
10) Statement Event ...
Appl Handle: 23
Appl Id: G91AA377.G576.00F306261BF2
Appl Seq number: 0001
Record is the result of a flush: FALSE
-------------------------------------------
Type :
Dynamic
Operation: Prepare
Section : 1
Creator : NULLID
Package : SYSSH200
Consistency Token : SYSLVL01
Package Version ID :
Cursor : SQL_CURSH200C1
Cursor was blocking: FALSE
Text : SELECT job FROM staff WHERE name = ?
|
清單 2摘自從 SQLJ 程序生成的事件監(jiān)視器的樣本輸出。輸出中的“Type: Static”和“Package: SRQT402”告訴您,對(duì) SRQT402 包靜態(tài)執(zhí)行了該語(yǔ)句。
清單 2. 從 SQLJ 程序生成的事件監(jiān)視器的樣本輸出
10) Statement Event ...
Appl Handle: 12
Appl Id: G91ABD18.G47D.00F306C01D63
Appl Seq number: 0001
Record is the result of a flush: FALSE
-------------------------------------------
Type :
Static
Operation: Execute
Section : 1
Creator : NULLID
Package :
SRQT402
Consistency Token : SARoQCAp
Package Version ID :
Cursor :
Cursor was blocking: FALSE
|
注:有些語(yǔ)句對(duì)于定制的 SQLJ 程序會(huì)正確執(zhí)行,但對(duì)于未定制的 SQLJ 程序就不會(huì)正確執(zhí)行。可滾動(dòng)游標(biāo)的 UPDATE/DELETE WHERE CURRENT OF 就是這樣一個(gè)示例。一般而言,如果底層 JDBC 驅(qū)動(dòng)程序不支持某個(gè)功能,那么未定制的 SQLJ 程序也不會(huì)支持該功能。
性能技巧: 對(duì)于單個(gè) select 查詢(xún),與盲目地對(duì)龐大的 JDBC ResultSets 執(zhí)行操作相比,可以通過(guò)使用由 SQLJ 提供的 SELECT INTO 語(yǔ)法來(lái)減少網(wǎng)絡(luò)活動(dòng)。
圖 3比較了用于單個(gè) select 查詢(xún)的 SQLJ 和 JDBC 語(yǔ)法。
圖 3. 使用 SQLJ 和 JDBC 檢索一個(gè)行
SQLJ 語(yǔ)法:
#sql [conCtx] { SELECT job INTO :job FROM staff WHERE name = :name };
JDBC 語(yǔ)法:
PreparedStatement pstmt = con.prepareStatement(
"SELECT job FROM staff WHERE name = ? FETCH FIRST 1 ROW ONLY" );
ResultSet rs = pstmt.executeQuery();
if ( rs.next() )
job = rs.getString(1);
else
job = null;
pstmt.close();
|
|
語(yǔ)法
圖 3表明 SQLJ 語(yǔ)法在簡(jiǎn)單性方面優(yōu)于 JDBC。SQLJ 的簡(jiǎn)單性受到了許多 Java 開(kāi)發(fā)人員的歡迎。編寫(xiě) SQLJ 模塊通常要比 JDBC 模塊簡(jiǎn)潔且容易。這暗示著 SQLJ 可以使開(kāi)發(fā)周期縮短并減少開(kāi)發(fā)和維護(hù)成本。 圖 4向您顯示了 SQLJ 可以多么簡(jiǎn)單地向數(shù)據(jù)庫(kù)插入一行數(shù)據(jù)。如果您已有了用其它語(yǔ)言(如 C 或 COBOL)編寫(xiě)的嵌入式 SQL 應(yīng)用程序,那么就可以使用 SQLJ 輕松地將應(yīng)用程序遷移到 Java。
圖 4. 使用 SQLJ vs. JDBC 插入一個(gè)行
SQLJ 語(yǔ)法:
sql [conCtx] { INSERT INTO sales VALUES(:date, :salesperson, :region, :sales) };
JDBC 語(yǔ)法:
PreparedStatement pstmt = con.prepareStatement( "INSERT INTO sales VALUES (?, ?, ?, ?)" );
// set input parameter
pstmt.setObject(1, date);
pstmt.setString(2, salesperson);
pstmt.setString(3, region);
pstmt.setInteger(4, sales);
pstmt.executeUpdate();
pstmt.close();
|
SQLJ 和 JDBC 互操作性
SQLJ 語(yǔ)言允許您在 SQLJ 應(yīng)用程序中使用 JDBC 語(yǔ)句。要使 JDBC 和 SQLJ 之間便于交互,SQLJ 提供了一種方法以便在同一應(yīng)用程序內(nèi)共享 SQLJ 連接和 JDBC 連接,這種方法還可以從 SQLJ 迭代器中獲取 JDBC 結(jié)果集,或從 JDBC 迭代器中獲取 SQLJ 結(jié)果集。
何時(shí)需要在 SQLJ 應(yīng)用程序中使用 JDBC? 您需要將 JDBC 用于動(dòng)態(tài)操作時(shí);即,在編寫(xiě)程序時(shí)不清楚 SQL 操作的時(shí)候。 清單 3演示了在 SQLJ 程序內(nèi)用 JDBC 來(lái)執(zhí)行動(dòng)態(tài)查詢(xún)(WHERE 子句中的名稱(chēng)在開(kāi)發(fā)時(shí)是未知的),以及如何將 JDBC 結(jié)果集轉(zhuǎn)換到 SQLJ 迭代器。
與 SQLJ 不同的是,JDBC 不能識(shí)別 SQLJ 語(yǔ)法,而且 SQL 語(yǔ)句不能嵌入到 JDBC 應(yīng)用程序。
清單 3. 將 JDBC 結(jié)果集轉(zhuǎn)換到 SQLJ 迭代器
Public class ResultSetInterop
{
#sql public static iterator Employees (String name, double salary);
public static void main(String[] argv) throws SQLException
{
// the code for creating the SQLJ connection context (conCtx) and
// the Connection object (con) is omitted
// create a JDBC statement object to execute a dynamic query
Statement stmt = con.createStatement();
String query = "SELECT name, salary FROM staff WHERE ";
query += argv[0];
ResultSet rs = stmt.executeQuery(query);
Employees SalReport;
// turn a JDBC result set to an SQLJ interator using the CAST statement
#sql [conCtx] SalReport = {
CAST :rs };
while (SalReport.next()) {
System.out.println( SalReport.name() + " earns " + SalReport.salary() );
}
SalReport.close();
stmt.close();
}
}
|
|
類(lèi)型和模式檢查
SQLJ 與 Java 類(lèi)似的一點(diǎn)是,它也是強(qiáng)類(lèi)型的。在將 SQLJ 源文件轉(zhuǎn)換成 Java 源文件時(shí),SQLJ 轉(zhuǎn)換程序會(huì)檢查 SQLJ 語(yǔ)法。這類(lèi)似于其它 DB2 預(yù)編譯器。而且,在轉(zhuǎn)換階段的 Java 編譯期間執(zhí)行迭代器數(shù)據(jù)類(lèi)型的轉(zhuǎn)換。例如,在禁止使用雙精度的迭代器列(如雇員工資)中,Java 編譯器就會(huì)阻止該列使用雙精度類(lèi)型。因此, String hv = employees.salary(); 這樣的賦值在編譯時(shí)就會(huì)生成一個(gè)錯(cuò)誤。另外,在概要文件定制期間也執(zhí)行聯(lián)機(jī)檢查,以便可以較早地捕獲編程錯(cuò)誤。
JDBC 不能在運(yùn)行時(shí)之前進(jìn)行語(yǔ)法或語(yǔ)義檢查。如果存在語(yǔ)法或語(yǔ)義錯(cuò)誤,那么在應(yīng)用程序運(yùn)行時(shí)任何此類(lèi)異常都會(huì)產(chǎn)生。
注:
- 在 V8.1 中,在概要文件定制期間執(zhí)行聯(lián)機(jī)檢查,而在以前的發(fā)行版中這一操作是在轉(zhuǎn)換階段執(zhí)行的。
- 有些 SQLJ 錯(cuò)誤只有在運(yùn)行時(shí)才被捕獲到。另外,不能動(dòng)態(tài)編譯的語(yǔ)句不會(huì)進(jìn)行聯(lián)機(jī)檢查。
差異匯總
表 1匯總了 SQLJ 和 JDBC 之間的差異。
表 1. 比較 SQLJ 和 JDBC
|
SQLJ |
JDBC |
標(biāo)準(zhǔn) |
ISO/ANSI(不屬于 J2EE) |
Sun(屬于 J2EE) |
SQL 規(guī)范級(jí)別 |
SQL-1999 |
N/A(必須至少支持 Entry Level SQL-92) |
安全性 |
強(qiáng) |
一般 |
性能 |
較快(在開(kāi)發(fā)期間創(chuàng)建了靜態(tài)存取方案) |
較慢(在應(yīng)用程序執(zhí)行期間創(chuàng)建了動(dòng)態(tài)存取方案) |
語(yǔ)法 |
高級(jí)(緊湊) |
低級(jí)(繁瑣) |
SQLJ 和 JDBC 互操作性 |
是 |
N/A |
類(lèi)型和模式檢查 |
強(qiáng)(在開(kāi)發(fā)期間執(zhí)行) |
弱(在運(yùn)行時(shí)期間執(zhí)行) |
V8.1 中的新增功能
DB2 UDB V8.1 提供了新設(shè)計(jì)的 SQLJ 驅(qū)動(dòng)程序,它有幾個(gè)新特性。新的 SQLJ 驅(qū)動(dòng)程序基于一種稱(chēng)為 Distributed Relational Database Architecture?(DRDA®)的開(kāi)放分布式協(xié)議。基于 CLI 的 JDBC 驅(qū)動(dòng)程序(類(lèi)型 2 和類(lèi)型 3)以及 V8.1 中引入的新的通用 JDBC 驅(qū)動(dòng)程序(類(lèi)型 2 和類(lèi)型 4)都支持該協(xié)議。
SQLJ 的主要增強(qiáng)功能可以概括如下:
新的 SQLJ 實(shí)用程序和運(yùn)行時(shí)
DB2 UDB V8.1 中的 SQLJ 實(shí)現(xiàn)了純 Java SQLJ 實(shí)用程序和運(yùn)行時(shí),并帶有一些新選項(xiàng)和可選的格式。新的運(yùn)行時(shí)性能比 V7 的性能好得多。
在 V8.1 中,SQLJ 轉(zhuǎn)換程序 sqlj 在缺省情況下總是編譯所生成的 Java 源文件。在 V7 中,這個(gè)編譯選項(xiàng)不能與某些 JDK 一起使用,因此您必須手工編譯 Java 文件。
V8.1 中新的概要文件打印程序 db2sqljprint 不再需要您提供 URL,而且它提供了有關(guān)要執(zhí)行的 SQL 語(yǔ)句的詳細(xì)信息,例如 DB2 語(yǔ)句的類(lèi)型、節(jié)號(hào)以及 DB2 結(jié)果集元數(shù)據(jù)信息。
消除了特定于平臺(tái)的文件
V8.1 中的 SQLJ 概要文件定制程序包含新的序列化概要文件格式,它不必使用 DBRM 文件和綁定文件(.bnd 文件)。新格式完全可以移植到所有平臺(tái)。它包含所有 BIND 操作所需的所有信息,用戶(hù)不必在目標(biāo)系統(tǒng)(UNIX®、Windows®、OS/390® 和 z/OS?)上重新定制序列化概要文件就可以部署在任何服務(wù)器平臺(tái)上。
V8 中的新特性
DB2 UDB V8.1 中添加的主要特性包括以下各項(xiàng):
使用 DataSource 創(chuàng)建 SQLJ 連接上下文
有了 V8.1 SQLJ,您可以使用 JDBC DataSource 接口來(lái)創(chuàng)建 SQLJ 連接。而且,缺省連接上下文的實(shí)現(xiàn)也更改了。要獲得缺省連接上下文,SQLJ 運(yùn)行時(shí)要執(zhí)行 JNDI 查詢(xún)以獲得 jdbc/defaultDataSource。如果沒(méi)有注冊(cè)任何 jdbc/defaultDataSource,那么在驅(qū)動(dòng)程序試圖訪問(wèn)上下文時(shí),就會(huì)拋出一個(gè)空上下文異常。因此,必須向 JNDI 注冊(cè) jdbc/defaultDataSource,或者通過(guò)調(diào)用 DefaultContext.setDefaultContext(userctxt) 來(lái)設(shè)置缺省上下文。
建議:在 SQLJ 子句中使用顯式的連接上下文。
清單 4. 使用數(shù)據(jù)源創(chuàng)建 SQLJ 連接上下文
// Create connection context class Ctx with the new dataSource keyword
#sql public static context Ctx with (dataSource="jdbc/sampledb");
String userid, password;
String empname;
?
// Create connection context object conCtx for the connection to jdbc/sampledb
Ctx conCtx = new Ctx(userid, password);
#sql [conCtx] { SELECT lastname INTO :empname FROM emp WHERE empno = '000010' };
?
conCtx.close();
|
|
可滾動(dòng)的迭代器
可滾動(dòng)的迭代器允許您向前移、向后移或移動(dòng)到指定行。與 JDBC 中可滾動(dòng)的游標(biāo)相似,可滾動(dòng)的迭代器可以是 不敏感的,也可以是 敏感的。
- 不敏感的迭代器意味著在迭代器打開(kāi)后,它不能看到底層表中的更改。不敏感的迭代器是只讀的。
- 敏感的迭代器意味著迭代器可以看到迭代器或其它處理對(duì)底層表所作的更改。例如, 清單 5中的代碼演示了如何使用指定的迭代器對(duì)雇員表的所有行以逆序方式檢索雇員號(hào)和雇員的姓氏。
清單 5. 使用可滾動(dòng)的迭代器
// Declare a scrollable iterator.
#sql iterator ScrollIter implements sqlj.runtime.Scrollable with (sensitivity = SENSITIVE)
(String EmpNo, String LastName);
{
ScrollIter scrlIter;
#sql [conCtx] scrlIter={ SELECT empno, lastname FROM emp };
scrlIter.afterLast();
while (scrlIter.previous())
{
System.out.println(scrlIter.EmpNo() + " " + scrlIter.LastName());
}
scrlIter.close();
}
|
|
批處理更新
批處理更新允許將語(yǔ)句集中到一起,隨后將其以批處理方式發(fā)送到數(shù)據(jù)庫(kù),一次執(zhí)行完這些語(yǔ)句。您可以在批處理更新中包含以下幾種類(lèi)型的語(yǔ)句:
- 搜索到的 INSERT、UPDATE 或 DELETE 語(yǔ)句
- CREATE、ALTER、DROP、GRANT 或 REVOKE 語(yǔ)句
- 只帶輸入?yún)?shù)的 CALL 語(yǔ)句
與 JDBC 不同,SQLJ 允許異構(gòu)批處理,這些批處理中包含帶有輸入?yún)?shù)或主機(jī)表達(dá)式的語(yǔ)句。因此在同一個(gè) SQLJ 語(yǔ)句批處理中可以包含同一語(yǔ)句的實(shí)例、不同語(yǔ)句的實(shí)例、帶輸入?yún)?shù)或主機(jī)表達(dá)式的語(yǔ)句的實(shí)例以及不帶輸入?yún)?shù)或主機(jī)表達(dá)式的語(yǔ)句的實(shí)例等。
建議:在關(guān)閉批處理或在結(jié)束使用 ExecutionContext(會(huì)使批處理打開(kāi))之前,要顯式地調(diào)用 executeBatch()。這將確保執(zhí)行經(jīng)過(guò)批處理的所有語(yǔ)句。
清單 6中的代碼段向您顯示了如何以批處理方式執(zhí)行更新操作來(lái)給所有管理人員加薪。
清單 6. 執(zhí)行批處理更新
#sql iterator getMgr(String);
{
getMgr deptIter;
String mgrnum = null;
int raise = 400;
int currentSalary;
String url = null, username = null, password = null;
testContext conCtx = new testContext (url, username, password, false);
// Acquire execution context.
// All statements that execute in a batch must use this execution context.
ExecutionContext exeCtx = new ExecutionContext();
// Invoke ExecutionContext.setBatching (true) to create a batch.
exeCtx.setBatching(true);
#sql [conCtx] deptIter = { SELECT mgrno FROM dept };
#sql {FETCH :deptIter INTO :mgrnum};
while (!deptIter.endFetch())
{
#sql [conCtx] {
SELECT SALARY INTO :currentSalary FROM emp WHERE empno = :mgrnum};
#sql [conCtx, exeCtx]
{ UPDATE emp SET SALARY = :(currentSalary+raise) WHERE empno =:mgrnum };
#sql { FETCH :deptIter INTO :mgrnum };
}
exeCtx.executeBatch();
exeCtx.setBatching(false);
#sql [conCtx] {COMMIT};
deptIter.close();
exeCtx.close();
conCtx.close();
}
|
結(jié)束語(yǔ)
相對(duì)于 JDBC,SQLJ 的 DB2 實(shí)現(xiàn)具有明顯的優(yōu)勢(shì)。在預(yù)編譯時(shí) SQLJ 較簡(jiǎn)單語(yǔ)法和類(lèi)型以及模式檢查大大降低了開(kāi)發(fā)成本。SQLJ 還具有在 SQLJ 應(yīng)用程序中嵌入 JDBC 語(yǔ)句這樣的靈活性。這意味著一個(gè)應(yīng)用程序可以同時(shí)利用 SQLJ 和 JDBC 的優(yōu)點(diǎn)。當(dāng)安全性和性能對(duì) Java 應(yīng)用程序至關(guān)重要時(shí),SQLJ 是正確的選擇。
更多信息
關(guān)于作者
 |

|
 |
Connie Tsui是 IBM 多倫多實(shí)驗(yàn)室 DB2 解決方案集成團(tuán)隊(duì)的專(zhuān)職軟件分析師。她從多倫多大學(xué)(University of Toronto)獲得了計(jì)算機(jī)科學(xué)學(xué)士學(xué)位。她目前主要從事 DB2 和 WebSphere® 的集成。
|
|