在數(shù)據(jù)庫(kù)應(yīng)用程序中使用存儲(chǔ)過(guò)程有許多好處,包括減少對(duì)網(wǎng)絡(luò)的使用、提高性能以及降低開發(fā)成本。Java 存儲(chǔ)過(guò)程是 DB2 支持的最流行的例程之一。原因之一是,由于 Java 編程語(yǔ)言非常流行,所以 Java 開發(fā)人員非常多。因此,在有多種語(yǔ)言可供選擇時(shí),Java 例程往往是首選的。
DB2 存儲(chǔ)過(guò)程不一定非用 Java 來(lái)編寫。如果業(yè)務(wù)邏輯只需要簡(jiǎn)單的存儲(chǔ)過(guò)程,那么可以考慮用 SQL Procedure Language(SQL PL)進(jìn)行存儲(chǔ)過(guò)程開發(fā)。SQL 存儲(chǔ)過(guò)程總是作為 受信任的 存儲(chǔ)過(guò)程運(yùn)行,并且因?yàn)樗鼈儾灰蕾囉谕獠?Java 虛擬機(jī)(Java Virtual Machine,JVM)進(jìn)程來(lái)裝載過(guò)程,所以比 Java 例程快。
使用 Java 存儲(chǔ)過(guò)程的好處與創(chuàng)建 Java 應(yīng)用程序時(shí)獲得的好處相同。Java 是非常安全的編程語(yǔ)言。用戶只能獲得 Java 字節(jié)碼。Java 代碼編譯一次,就能夠在支持 JVM 的任何計(jì)算機(jī)和操作系統(tǒng)上運(yùn)行。因?yàn)?Java 代碼在單獨(dú)的 JVM 中運(yùn)行,所以 JVM 能夠正確地處理(可能導(dǎo)致 JVM 崩潰的)危險(xiǎn)操作。不需要實(shí)現(xiàn)單獨(dú)的基礎(chǔ)設(shè)施來(lái)處理危險(xiǎn)狀況,因?yàn)?Java 具有捕獲異常的內(nèi)置機(jī)制。
在本文中,我們有時(shí)將 Java 存儲(chǔ)過(guò)程稱為例程。在 DB2 UDB 中存儲(chǔ)過(guò)程和例程是同義的。在 DB2 V8 中引入了例程的概念,它既表示存儲(chǔ)過(guò)程,也表示用戶定義函數(shù)(UDF)。
本文討論在開發(fā)或運(yùn)行 Java 存儲(chǔ)過(guò)程的過(guò)程中可能遇到的常見錯(cuò)誤消息。在開始討論之前,我們先討論 Java 存儲(chǔ)過(guò)程開發(fā)的重要概念和配置參數(shù)。接下來(lái),描述如何啟用 DB2 Java。需要建立 Java 環(huán)境才能成功地調(diào)用 Java 存儲(chǔ)過(guò)程。
關(guān)鍵概念
以下概念對(duì)于理解存儲(chǔ)過(guò)程在 DB2 環(huán)境中如何工作非常重要:
-
FENCED 或 NOT FENCED:
這個(gè)子句指定例程是否被認(rèn)為可以在數(shù)據(jù)庫(kù)管理器操作環(huán)境的進(jìn)程或地址空間中“安全地”運(yùn)行。
如果存儲(chǔ)過(guò)程被注冊(cè)為 FENCED,那么數(shù)據(jù)庫(kù)管理器就禁止過(guò)程訪問(wèn)它的內(nèi)部資源(比如數(shù)據(jù)緩沖區(qū))。大多數(shù)例程都有作為 FENCED 或 NOT FENCED 運(yùn)行的選項(xiàng)。但是,Java 例程只能注冊(cè)為 FENCED。一般來(lái)說(shuō),作為 FENCED 運(yùn)行的例程執(zhí)行得沒(méi)有作為 NOT FENCED 運(yùn)行的相似例程那么快。這是因?yàn)?NOT FENCED 例程可以在數(shù)據(jù)庫(kù)引擎內(nèi)利用進(jìn)程間通信(IPC)。
對(duì)沒(méi)有經(jīng)過(guò)徹底測(cè)試的例程使用 NOT FENCED,可能會(huì)破壞 DB2 完整性。DB2 對(duì)于許多常見的意外故障類型采取了某些保護(hù)措施,但是在使用 NOT FENCED 例程時(shí)無(wú)法保證完全的完整性。NOT FENCED 例程常常被稱為受信任的(trusted)。聲明為受信任的例程在數(shù)據(jù)庫(kù)管理器的地址空間中運(yùn)行。
將例程注冊(cè)為 NOT FENCED 需要 SYSADM 特權(quán)、DBADM 特權(quán)或一個(gè)特殊的特權(quán)(CREATE_NOT_FENCED)。定義為 NOT THREADSAFE 的例程只能指定 FENCED。
-
THREADSAFE 或 NOT THREADSAFE: 這個(gè)子句指定這個(gè)例程是否可以安全地在其他例程的進(jìn)程中執(zhí)行(THREADSAFE 是可以,NOT THREADSAFE 是不可以)。
如果過(guò)程定義為 THREADSAFE,數(shù)據(jù)庫(kù)管理器就可以在其他例程的進(jìn)程中調(diào)用這個(gè)過(guò)程。一般來(lái)說(shuō),要想定義為 THREADSAFE,例程不應(yīng)該使用任何全局或靜態(tài)數(shù)據(jù)區(qū)域。許多編程參考資料討論了如何編寫線程安全的例程。FENCED 和 NOT FENCED 過(guò)程都可以是 THREADSAFE 的。
如果過(guò)程定義為 NOT THREADSAFE,數(shù)據(jù)庫(kù)管理器就絕不會(huì)在其他例程的進(jìn)程中調(diào)用這個(gè)過(guò)程。
在 Java 存儲(chǔ)過(guò)程中,THREADSAFE 是默認(rèn)的,無(wú)論它被聲明為 FENCED 還是 NOT FENCED 存儲(chǔ)過(guò)程。
|
|
配置參數(shù)
DB2 有許多配置參數(shù)。一些參數(shù)在數(shù)據(jù)庫(kù)級(jí)上定義,其他參數(shù)在數(shù)據(jù)庫(kù)管理級(jí)上定義。影響存儲(chǔ)過(guò)程行為的大多數(shù)參數(shù)是在實(shí)例級(jí)(即數(shù)據(jù)庫(kù)管理級(jí))上定義的。
-
KEEPFENCED: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。在以前的 DB2 UDB 版本中,它被稱為 KEEPDARI。這個(gè)參數(shù)指出,在完成一個(gè)防護(hù)模式例程調(diào)用之后,是否保留防護(hù)模式進(jìn)程(db2fmp)。防護(hù)模式進(jìn)程是作為單獨(dú)的系統(tǒng)實(shí)體創(chuàng)建的,以便將用戶編寫的防護(hù)模式代碼與數(shù)據(jù)庫(kù)管理器代理進(jìn)程隔離開來(lái)。這個(gè)參數(shù)只能應(yīng)用于數(shù)據(jù)庫(kù)服務(wù)器。在開發(fā)存儲(chǔ)過(guò)程時(shí),強(qiáng)烈建議將這個(gè)參數(shù)設(shè)置為 NO,這樣,調(diào)用存儲(chǔ)過(guò)程時(shí)總會(huì)得到全新的存儲(chǔ)過(guò)程副本。如果存儲(chǔ)過(guò)程常常重新編譯,那么這特別重要。在生產(chǎn)環(huán)境中,應(yīng)該將這個(gè)參數(shù)設(shè)置為 YES,因?yàn)樗鼤?huì)顯著地影響性能。NOT FENCED 存儲(chǔ)過(guò)程不受這個(gè)配置參數(shù)影響,因?yàn)樗鼈儾辉?db2fmp 進(jìn)程中運(yùn)行。
-
FENCED_POOL: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。它代表系統(tǒng)上緩存的空閑防護(hù)模式進(jìn)程(db2fmp)的數(shù)量。對(duì)于線程化的 db2fmp 進(jìn)程(為線程安全的存儲(chǔ)過(guò)程和 UDF 提供服務(wù)的進(jìn)程),這個(gè)參數(shù)代表每個(gè) db2fmp 進(jìn)程中緩存的線程數(shù)量。對(duì)于非線程化的 db2fmp 進(jìn)程,這個(gè)參數(shù)代表緩存的進(jìn)程數(shù)量。
-
NUM_INITFENCED: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。這個(gè)參數(shù)表示在 DB2START 時(shí)在 db2fmp 池中創(chuàng)建的非線程化空閑 db2fmp 進(jìn)程的初始數(shù)量。如果沒(méi)有指定 KEEPFENCED,這個(gè)參數(shù)就被忽略。
-
JDK_PATH: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。這個(gè)參數(shù)指出用來(lái)執(zhí)行 Java 存儲(chǔ)過(guò)程的 JVM 或 Java Development Kit(JDK)的位置。這是一個(gè)非常重要的參數(shù)。它的值應(yīng)該設(shè)置為包含 JVM Java 可執(zhí)行文件的 “bin” 目錄的上一級(jí)目錄的完整路徑。在 Windows? 平臺(tái)上的一個(gè)例子是 C:\Program Files\IBM\SQLLIB\java\jdk。UNIX? 例子是 /usr/java1.3.1。JVM 級(jí)別也非常重要,因?yàn)楦鶕?jù)使用的 db2level 和平臺(tái)級(jí)別,DB2 UDB 只支持某些 JVM 級(jí)別。(這個(gè)問(wèn)題將在本文稍后討論。)
-
JAVA_HEAP_SZ: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。這個(gè)參數(shù)決定為 Java 存儲(chǔ)過(guò)程和 UDF 服務(wù)的 Java 解釋器所使用的堆的最大大小。為了避免在 Java 存儲(chǔ)過(guò)程中耗盡內(nèi)存,可以增加這個(gè)值。但是,如果在環(huán)境中要調(diào)用許多存儲(chǔ)過(guò)程(即,每個(gè) JVM 都會(huì)分配這么多堆空間),那么分配太多內(nèi)存也是有害的。一般規(guī)則是保持 JAVA_HEAP_SZ 為默認(rèn)設(shè)置,即 512(4K 頁(yè))。
-
ASLHEAPSZ: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。應(yīng)用程序支持層堆是本地應(yīng)用程序和與它相關(guān)聯(lián)的代理之間的通信緩沖區(qū)。這個(gè)緩沖區(qū)作為每個(gè)數(shù)據(jù)庫(kù)管理器代理共享的內(nèi)存分配。這個(gè)參數(shù)確定緩沖區(qū)的大小,用于在例程和發(fā)出調(diào)用的應(yīng)用程序之間傳遞參數(shù)。存儲(chǔ)過(guò)程中的參數(shù)數(shù)量和參數(shù)大小明確地影響這個(gè)配置參數(shù)。系統(tǒng)上允許同時(shí)存在的 db2fmp 進(jìn)程的最大數(shù)量也受這個(gè)參數(shù)的影響。
-
QUERY_HEAP_SZ: 這是一個(gè)數(shù)據(jù)庫(kù)管理器配置(DBM CFG)參數(shù)。這個(gè)參數(shù)指定可以分配給查詢堆的最大內(nèi)存量。查詢堆用于在代理的私有內(nèi)存中存儲(chǔ)每個(gè)查詢。每個(gè)查詢的信息包括輸入和輸出 SQLDA、語(yǔ)句文本、SQLCA、包名、創(chuàng)建者、區(qū)號(hào)和一致性符號(hào)。提供這個(gè)參數(shù)是為了確保應(yīng)用程序不會(huì)不必要地消耗代理中的大量虛擬內(nèi)存。如果這個(gè)參數(shù)設(shè)置得過(guò)低,那么執(zhí)行復(fù)雜 SQL 的存儲(chǔ)過(guò)程會(huì)導(dǎo)致 db2fmp 進(jìn)程意外終止。
-
DB2_FMP_COMM_HEAPSZ: 這是一個(gè) db2set 注冊(cè)表參數(shù)。這個(gè)參數(shù)可應(yīng)用于所有平臺(tái),只有 AIX 32 位平臺(tái)除外,在這種平臺(tái)上這個(gè)值預(yù)定義為 256MB。這個(gè)變量指定防護(hù)例程調(diào)用(比如存儲(chǔ)過(guò)程或用戶定義函數(shù)調(diào)用)所使用的池的大小(以 4 KB 頁(yè)為單位)。每個(gè)防護(hù)例程所使用的空間是 ASLHEAPSZ 配置參數(shù)值的兩倍。如果在系統(tǒng)上運(yùn)行大量防護(hù)例程,那么可能需要增加這個(gè)變量的值。如果運(yùn)行的防護(hù)例程很少,可以降低這個(gè)值。將這個(gè)值設(shè)置為 0 就表示不創(chuàng)建池,因此不能調(diào)用防護(hù)例程。可以用以下公式計(jì)算系統(tǒng)上可以同時(shí)運(yùn)行的 db2fmp 進(jìn)程的數(shù)量:
Maximum Number of db2fmps = DB2_FMP_COMM_HEAPSZ / (2*ASLHEAPSZ)
|
|
|
設(shè)置 Java 環(huán)境
需要執(zhí)行幾個(gè)步驟,然后才能編譯 Java 存儲(chǔ)過(guò)程。本節(jié)討論設(shè)置用于運(yùn)行 Java 過(guò)程的系統(tǒng)所需的步驟。
兼容的 JDK/JVM 級(jí)別
在開始之前,首先確保數(shù)據(jù)庫(kù)服務(wù)器上安裝了兼容的 JDK/JVM。每種操作系統(tǒng)支持不同的 JDK 級(jí)別。如果數(shù)據(jù)庫(kù)實(shí)例配置為 64 位而不是 32 位,那么這特別重要。
支持的 JDK/JVM 級(jí)別的兼容性表可以在以下網(wǎng)頁(yè)上找到:http://www-306.ibm.com/software/data/db2/udb/ad/v8/java/。
同一個(gè)系統(tǒng)上可以安裝多個(gè) JVM。為了決定在執(zhí)行 Java 存儲(chǔ)過(guò)程時(shí)使用哪個(gè) JVM,DB2 讀取 JDK_PATH 數(shù)據(jù)庫(kù)管理器配置參數(shù)。需要確保 JDK_PATH 指向與環(huán)境兼容的 JVM。
設(shè)置 Java 環(huán)境
DB2 數(shù)據(jù)庫(kù)服務(wù)器的平臺(tái)需要正確地設(shè)置才能使用 Java。對(duì)于 Java 支持,每種平臺(tái)可能有自己的需求。
對(duì)于 UNIX 平臺(tái)一般的 Java 設(shè)置需求可以在以下網(wǎng)頁(yè)上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0004675.htm
對(duì)于 Windows 平臺(tái)一般的 Java 設(shè)置需求可以在以下網(wǎng)頁(yè)上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0006428.htm
HPUX 和 Linux
HPUX 和 Linux 對(duì)于 Java 支持有額外的需求:
防護(hù) id
為了執(zhí)行 FENCED 存儲(chǔ)過(guò)程,DB2 通過(guò)防護(hù) id 方式提供了額外的安全層。這個(gè) id(和組)應(yīng)該在創(chuàng)建 DB2 實(shí)例時(shí)創(chuàng)建。可以從以下網(wǎng)頁(yè)獲得關(guān)于這個(gè) id 的更多信息:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/admin/t0005077.htm
配置參數(shù)
前面的 配置參數(shù) 小節(jié)提到了一組重要的配置參數(shù)。大多數(shù)這些參數(shù)可以保持默認(rèn)設(shè)置。但是,當(dāng)遇到問(wèn)題(特別是性能問(wèn)題或內(nèi)存問(wèn)題)時(shí),應(yīng)該檢查和調(diào)整 DB2 配置參數(shù),使之適合您的系統(tǒng),這是非常重要的。
數(shù)據(jù)庫(kù)特權(quán)
在大多數(shù)情況下,應(yīng)用程序開發(fā)人員將開發(fā)存儲(chǔ)過(guò)程。這一般意味著 DB2 管理員可能必須向應(yīng)用程序開發(fā)人員提供必需的特權(quán),讓他們能夠創(chuàng)建和維護(hù)這些存儲(chǔ)過(guò)程。對(duì)于 Java 存儲(chǔ)過(guò)程開發(fā)人員,可考慮提供以下特權(quán):EXECUTE、CREATE_EXTERNAL_ROUTINE、CREATE_NOT_FENCED_ROUTINE、IMPLICIT_SCHEMA、CREATEIN 和 BINDADD。關(guān)于數(shù)據(jù)庫(kù)特權(quán)的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/admin/c0005524.htm
創(chuàng)建和部署 Java 例程
設(shè)置好環(huán)境之后,就應(yīng)該能夠創(chuàng)建和部署自己的 Java(或 SQLJ)存儲(chǔ)過(guò)程。DB2 Application Development Client(如果安裝了)包含一組示例,您在初次創(chuàng)建存儲(chǔ)過(guò)程時(shí)可以參考這些示例。Java 存儲(chǔ)過(guò)程示例位于 sqllib/samples/java/jdbc 目錄中,稱為 SpServer.java。SQLJ 存儲(chǔ)過(guò)程示例位于 sqllib/samples/java/sqlj 目錄,稱為 SpServer.sqlj。
編寫自己的例程
在編寫自己的存儲(chǔ)過(guò)程時(shí)需要考慮一些事情。需要決定為存儲(chǔ)過(guò)程采用哪種參數(shù)傳遞技術(shù)。DB2 UDB 對(duì)于 Java 應(yīng)用程序支持兩種參數(shù)風(fēng)格:
-
PARAMETER STYLE JAVA —— 這意味著存儲(chǔ)過(guò)程將使用符合 Java 語(yǔ)言和 SQLJ 例程規(guī)范的參數(shù)傳遞約定。IN/OUT 和 OUT 參數(shù)將作為單項(xiàng)數(shù)組傳遞,以便于返回值。這只能在使用 LANGUAGE JAVA 時(shí)指定。PARAMETER STYLE JAVA 過(guò)程不支持 DBINFO 或 PROGRAM TYPE 子句。
-
PARAMETER STYLE DB2GENERAL —— 這意味著存儲(chǔ)過(guò)程將使用為 Java 方法定義的參數(shù)傳遞約定。這只能在使用 LANGUAGE JAVA 時(shí)指定。PARAMETER STYLE DB2GENERAL 仍然可以用于在 Java 例程中啟用以下特性的實(shí)現(xiàn):表函數(shù)、scratchpad、對(duì) DBINFO 結(jié)構(gòu)進(jìn)行訪問(wèn)以及對(duì)函數(shù)或方法進(jìn)行 FINAL CALL(和單獨(dú)的首次調(diào)用)。為了使用 DB2GENERAL 參數(shù)風(fēng)格,需要確保存儲(chǔ)過(guò)程的類擴(kuò)展了
COM.ibm.db2.app.StoredProc 。關(guān)于 PARAMETER STYLE DB2GENERAL 的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/c0000420.htm
在 CREATE 語(yǔ)句中使用 PARAMETER STYLE JAVA 子句注冊(cè) Java 例程。
與其他任何應(yīng)用程序一樣,存儲(chǔ)過(guò)程需要一個(gè) Connection context 。在 Java 和 JDBC 中,這是使用來(lái)自 java.sql.* 類的 Connection 對(duì)象完成的。調(diào)用存儲(chǔ)過(guò)程的應(yīng)用程序?qū)⒔⑦B接。所以在 Java 存儲(chǔ)過(guò)程中,以默認(rèn)連接 方式建立連接,如清單 1 所示。
清單 1. 一個(gè)名為 INSERT_JAVASP 的示例存儲(chǔ)過(guò)程
1 //The simplest JAVA SP
2 import java.sql.*;
3
4 public class INSERT_JAVASP
5 {
6 public static void iNSERT_JAVASP (String input) throws SQLException,
Exception
7 {
8 int errorCode;
9
10 try
11 {
12 // get caller's connection to the database
13 Connection con = DriverManager.getConnection("jdbc:default:connection");
14
15 String query = "INSERT INTO CWYLAW.StoreData (c) VALUES (?)";
16
17 PreparedStatement pstmt = con.prepareStatement(query);
18 pstmt.setString(1, input);
19 pstmt.executeUpdate();
20
21 }
22 catch (SQLException sqle)
23 {
24 errorCode = sqle.getErrorCode();
25 throw new SQLException( errorCode " FAILED" );
26 }
27 }
28 }
|
在清單 1 的第 13 行上,Connection 對(duì)象(con )被建立為 “默認(rèn)” 連接。調(diào)用存儲(chǔ)過(guò)程的應(yīng)用程序?qū)⒃谡{(diào)用過(guò)程之前建立這個(gè)連接。使用默認(rèn)連接時(shí),存儲(chǔ)過(guò)程從調(diào)用者那里獲得它的連接屬性。這里顯示的例子是一個(gè) Java 存儲(chǔ)過(guò)程,它接受一個(gè)輸入?yún)?shù)并且將其值插入 CWYLAW.StoreData 表。
對(duì)于使用例程的限制
對(duì)于為 DB2 UDB 開發(fā)存儲(chǔ)過(guò)程,有幾個(gè)限制。一定要檢查 DB2 Infocenter 的以下部分,確保自己了解這些限制:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/c0009198.htm
Java 類型映射
Java 支持自己的一組數(shù)據(jù)類型。DB2 也有自己的一組數(shù)據(jù)類型。例如,DB2 數(shù)據(jù)類型 VARCHAR 在 Java 中不存在。但是,Java 有一個(gè) String 對(duì)象,可以替代這種數(shù)據(jù)類型。DB2 UDB 有一組 “首選的” 數(shù)據(jù)類型映射,適用于 Java 應(yīng)用程序和存儲(chǔ)過(guò)程。表 1(引用于 Infocenter —— 參見 參考資料)顯示了這些映射。
Java 數(shù)據(jù)類型映射
SQL 類型 |
JDBC 2.0 類型 |
Java 類型 |
BIGINT |
BIGINT |
long |
BLOB |
BLOB |
java.sql.Blob |
CHAR |
CHAR |
String |
CHAR FOR BIT DATA |
BINARY |
byte[] |
CLOB |
CLOB |
java.sql.Clob |
DATE |
DATE |
java.sql.Date |
DBCLOB |
CLOB |
java.sql.Clob |
DECIMAL |
DECIMAL |
java.math.BigDecimal |
DOUBLE |
DOUBLE |
double |
FLOAT |
FLOAT |
double |
INTEGER |
INTEGER |
int |
GRAPHIC |
CHAR |
String |
LONG VARCHAR |
LONGVARCHAR |
String |
LONG VARCHAR FOR BIT DATA |
LONGVARBINARY |
byte[] |
LONGVARGRAPHIC |
LONGVARCHAR |
String |
NUMERIC |
NUMERIC |
java.math.BigDecimal |
REAL |
REAL |
float |
SMALLINT |
SMALLINT |
short |
TIME |
TIME |
java.sql.Time |
TIMESTAMP |
TIMESTAMP |
java.sql.Timestamp |
VARCHAR |
VARCHAR |
String |
VARCHAR FOR BIT DATA |
VARBINARY |
byte[] |
VARGRAPHIC |
VARCHAR |
String |
編譯例程
創(chuàng)建了存儲(chǔ)過(guò)程之后,需要對(duì)它進(jìn)行編譯。使用系統(tǒng)上安裝的 JDK,用以下命令對(duì)過(guò)程進(jìn)行編譯:javac INSERT_JAVASP.java
這生成一個(gè)類文件。可以將這個(gè)類文件轉(zhuǎn)移到 sqllib/function 目錄(這是 DB2 獲得存儲(chǔ)過(guò)程可執(zhí)行文件的默認(rèn)位置),也可以將它轉(zhuǎn)移到您選擇的另一個(gè)位置(并且在 CREATE PROCEDURE 命令中使用這個(gè)定制的路徑)。
另一個(gè)辦法是將類文件打包到 JAR 文件中,并且部署 JAR 文件。可以使用以下命令將類文件打包到 JAR 文件中:jar -cvf INSERT_JAVASP.jar INSERT_JAVASP.class
關(guān)于放置 Java 類的位置的更多信息,請(qǐng)閱讀 Infocenter 的以下部分:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/c0006348.htm.
SQLJ 例程
在編寫 SQLJ 存儲(chǔ)過(guò)程時(shí),需要執(zhí)行兩個(gè)額外的步驟:
- 使用 DB2 SQLJ Translator 翻譯 SQLJ 源代碼。這會(huì)將
sqlj 代碼轉(zhuǎn)換成 java 代碼,并且創(chuàng)建一個(gè) SQLJ 可序列化(.ser)文件。
- 定制這個(gè)可序列化文件,使嵌入語(yǔ)句的訪問(wèn)計(jì)劃被存儲(chǔ)到包中(或綁定文件中)。這需要使用
db2sqljcustomize 命令。
關(guān)于 SQLJ 的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0007588.htm
數(shù)據(jù)庫(kù)服務(wù)器上的 JAR 文件管理
如果使用 JAR 文件而不是類文件,就需要采取一些額外的步驟,使 DB2 認(rèn)識(shí)到 JAR 文件是存儲(chǔ)過(guò)程類的容器。DB2 附帶四個(gè)內(nèi)置的存儲(chǔ)過(guò)程,幫助管理 JAR 文件。
-
SQLJ.INSTALL_JAR :這將把 JAR 文件 “安裝” 到 DB2 中,這樣,當(dāng) DB2 類裝載器尋找要裝載的存儲(chǔ)過(guò)程庫(kù)時(shí),它會(huì)找到并且裝載這個(gè)存儲(chǔ)過(guò)程(而不是同名的另一個(gè)存儲(chǔ)過(guò)程)。
語(yǔ)法:CALL sqlj.install_jar( jar-url, jar-id )
-
SQLJ.REPLACE_JAR:這將用一個(gè)新副本 “替換” DB2 中的 JAR 文件。如果存儲(chǔ)過(guò)程近來(lái)由于任何變更而重新編譯過(guò),那么這個(gè)操作特別有用。這樣,DB2 類裝載器將在運(yùn)行時(shí)重新裝載具有新內(nèi)容的 JAR 文件并且使用新內(nèi)容。
語(yǔ)法:CALL sqlj.replace_jar( jar-url, jar-id )
-
SQLJ.REMOVE_JAR:這將從 DB2 實(shí)例中 “刪除” JAR 文件。如果您打算刪除存儲(chǔ)過(guò)程并且不會(huì)重新創(chuàng)建它,那么這個(gè)操作就有用了。這樣,DB2 就不會(huì)在內(nèi)存中保留這個(gè) JAR 文件的副本。
語(yǔ)法:CALL sqlj.remove_jar( jar-id )
-
SQLJ.REFRESH_CLASSES:這將在 DB2 實(shí)例中 “刷新” 一個(gè) JAR 文件中包含的所有類。當(dāng)更新 Java 例程類時(shí),需要這樣做。這使 DB2 裝載新的類。如果沒(méi)有使用這個(gè)命令,DB2 將使用類的舊版本。這可以與 SQLJ.REPLACE_JAR 結(jié)合使用。
語(yǔ)法:CALL sqlj.refresh_classes( void )
關(guān)于 JAR 文件管理的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/r0006425.htm 和 http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0006410.htm
注冊(cè)例程
在編譯了存儲(chǔ)過(guò)程(并且可選地將它存儲(chǔ)在 JAR 文件中),并將它轉(zhuǎn)移到某個(gè)位置之后,可以對(duì)存儲(chǔ)過(guò)程進(jìn)行注冊(cè),使應(yīng)用程序可以引用它。
為此,需要使用 CREATE PROCEDURE 語(yǔ)句。在 CREATE PROCEDURE 語(yǔ)句中,可以為存儲(chǔ)過(guò)程指定幾個(gè)選項(xiàng)。下面是其中幾個(gè)重要的選項(xiàng):
-
SPECIFIC:這在 DB2 編目中惟一地標(biāo)識(shí)存儲(chǔ)過(guò)程名。一般來(lái)說(shuō),“SPECIFIC” 名稱匹配存儲(chǔ)過(guò)程名。
-
DYNAMIC RESULT SETS:這決定存儲(chǔ)過(guò)程是否返回一個(gè)結(jié)果集。存儲(chǔ)過(guò)程也可能返回多個(gè)結(jié)果集。這個(gè)選項(xiàng)決定過(guò)程將返回多少結(jié)果集。
-
LANGUAGE:這應(yīng)該設(shè)置為 JAVA。對(duì)于 SQLJ 存儲(chǔ)過(guò)程,也使用 JAVA。
-
EXTERNAL NAME:這個(gè)參數(shù)決定某個(gè)存儲(chǔ)過(guò)程的類文件或 JAR 文件的位置以及文件內(nèi)的方法。文件的默認(rèn)位置是 sqllib/function 文件夾。也可以指定文件實(shí)際位置的完整路徑。EXTERNAL NAME 子句的格式如下:
‘jar-id!class_id.method_id’ 或 ‘class_id.method_id’ 。
-
FENCED / NOT FENCED:這個(gè)參數(shù)決定存儲(chǔ)過(guò)程是聲明為 FENCED,還是 NOT FENCED。只有在您認(rèn)為代碼能夠安全執(zhí)行的情況下,才應(yīng)該使用 NOT FENCED 存儲(chǔ)過(guò)程。
-
THREADSAFE / NOT THREADSAFE:這個(gè)參數(shù)決定 FENCED 存儲(chǔ)過(guò)程的執(zhí)行是否是線程安全的。這只對(duì)定義為 FENCED 的過(guò)程起作用,因?yàn)?NOT FENCED 過(guò)程總被定義為 THREADSAFE。
-
PARAMETER STYLE:對(duì)于 Java 例程,參數(shù)風(fēng)格只能是 PARAMETER STYLE JAVA 或 PARAMETER STYLE DB2GENERAL。
關(guān)于 CREATE PROCEDURE 語(yǔ)句的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/admin/r0008328.htm
清單 2 顯示一個(gè) CREATE PROCEDURE 語(yǔ)句示例,其中使用了一些選項(xiàng)。
清單 2. CREATE PROCEDURE 語(yǔ)句示例
CREATE PROCEDURE INSERT_JAVASP (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT_JAVASP!iNSERT_JAVASP'
;
|
調(diào)用例程
一旦對(duì)存儲(chǔ)過(guò)程進(jìn)行了注冊(cè),首先要做的是調(diào)用它,確保它按照預(yù)期和設(shè)計(jì)進(jìn)行工作。DB2 有一個(gè) “CALL” 命令,可以使用它調(diào)用任何存儲(chǔ)過(guò)程。在大多數(shù)情況下,希望讓應(yīng)用程序使用參數(shù)標(biāo)志等動(dòng)態(tài)地調(diào)用存儲(chǔ)過(guò)程。請(qǐng)閱讀 Application Development Guide,以便確定從應(yīng)用程序中調(diào)用過(guò)程的最佳方式。
然而,DB2 命令行處理程序(CLP)可以使用以下語(yǔ)法調(diào)用存儲(chǔ)過(guò)程:
CALL proc-name( [parm1, parm2...] ) 其中的 parm1、parm2 等等是參數(shù)。如果參數(shù)是基于字符的輸入?yún)?shù),那么在單引號(hào)中指定字面值。如果參數(shù)是基于數(shù)值的輸入?yún)?shù),那么按原樣指定字面值。如果參數(shù)是輸出參數(shù),那么使用‘?’字符表示輸出參數(shù)。例如:
$ db2 "CALL SHAKEBS.TESTPROC('hello', 'world', 1, 2.5, ?, 'testing')"
|
在這個(gè)例子中,一共有 6 個(gè)參數(shù)。第一個(gè)、第二個(gè)和第六個(gè)參數(shù)都是字符字面值。第三個(gè)參數(shù)是數(shù)值字面值,適用于 integer 或 smallint 這樣的數(shù)據(jù)類型。第四個(gè)參數(shù)也是數(shù)值字面值,但是因?yàn)樗?shù)點(diǎn),所以應(yīng)該被看作 double、float 或 decimal 類型。因?yàn)榈谖鍌€(gè)參數(shù)是問(wèn)號(hào)(?),所以它表示輸出參數(shù)。因此,當(dāng)這個(gè)存儲(chǔ)過(guò)程被調(diào)用時(shí),它將在這個(gè)輸出參數(shù)中返回一個(gè)值。
關(guān)于 “CALL” 命令的更多信息,請(qǐng)參閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0011378.htm、http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0009000.htm 和 http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0007055.htm。
常見問(wèn)題
現(xiàn)在,讓我們看看應(yīng)用程序開發(fā)人員在開發(fā)和執(zhí)行 Java(或 SQLJ)存儲(chǔ)過(guò)程時(shí)可能遇到的一些常見問(wèn)題。本文的 下載 小節(jié)中的一個(gè) zip 文件提供了所有例子。請(qǐng)注意,這些例子中大部分都要求在服務(wù)器上的數(shù)據(jù)庫(kù)管理器配置文件中設(shè)置 KEEPFENCED=NO。
SQL4301 RC=0
清單 3 顯示第一個(gè)錯(cuò)誤的例子,sqlcode 為 SQL4301,返回碼為 0。
清單 3. SQL4301 rc=0 示例 1:Windows 上的 INSERT_JAVASP.java
D:\>javac INSERT_JAVASP.java
D:\>copy INSERT_JAVASP.class "C:\Program Files\IBM\SQLLIB\Function"
1 file(s) copied.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT_JAVASP (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT_JAVASP!iNSERT_JAVASP'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('D')
SQL4301N Java or .NET interpreter startup or communication failed, reason
code "0". SQLSTATE=58004
|
這個(gè)操作失敗并且顯示 SQL4301 rc=0 錯(cuò)誤消息。為什么呢?檢查 JDK_PATH 數(shù)據(jù)庫(kù)管理器配置參數(shù)的設(shè)置是否正確。JDK_PATH 應(yīng)該設(shè)置為用來(lái)執(zhí)行 Java 存儲(chǔ)過(guò)程的 JVM/JDK 的 “bin” 的上一級(jí)目錄。為了糾正這個(gè)問(wèn)題,檢查數(shù)據(jù)庫(kù)管理器配置參數(shù) JDK_PATH,并且修改它。
清單 4. SQL4301 rc=0 示例 1:數(shù)據(jù)庫(kù)管理器配置文件的片段
D:\>db2 get dbm cfg
Database Manager Configuration
Node type = Enterprise Server Edition with local and remote clients
Database manager configuration release level = 0x0a00
Maximum total of files open (MAXTOTFILOP) = 16000
CPU speed (millisec/instruction) (CPUSPEED) = 9.368161e-007
Communications bandwidth (MB/sec) (COMM_BANDWIDTH) = 1.000000e 002
Max number of concurrently active databases (NUMDB) = 8
Data Links support (DATALINKS) = NO
Federated Database System Support (FEDERATED) = NO
Transaction processor monitor name (TP_MON_NAME) =
Default charge-back account (DFT_ACCOUNT_STR) =
Java Development Kit installation path (JDK_PATH) = C:\PROGRA~1\IBM\
SQLLIB\java
...
|
注意,JDK_PATH 沒(méi)有指向 “bin” 的上一級(jí)目錄。這需要修改,如清單 5 所示。
清單 5. SQL4301 rc=0 示例 1:更新數(shù)據(jù)庫(kù)管理器配置文件
D:\>db2 update dbm cfg using JDK_PATH C:\PROGRA~1\IBM\SQLLIB\java\jdk
DB20000I The UPDATE DATABASE MANAGER CONFIGURATION command
completed successfully.
D:\>db2stop force
09/25/2005 14:33:16 0 0 SQL1064N DB2STOP processing was successful.
SQL1064N DB2STOP processing was successful.
D:\>db2start
09/25/2005 14:33:46 0 0 SQL1063N DB2START processing was successful.
SQL1063N DB2START processing was successful.
D:\>db2 connect to sample
Database Connection Information
Database server = DB2/NT 8.2.3
SQL authorization ID = SHAKEBS
Local database alias = SAMPLE
D:\>db2 call INSERT_JAVASP('D')
Return Status = 0
D:\>db2 "select * from CWYLAW.StoreData"
C
---
D
1 record(s) selected.
|
清單 6 顯示 SQL4301 rc=0 錯(cuò)誤的另一個(gè)例子。這是由于使用了不兼容的 JVM 造成的。64 位實(shí)例需要 64 位的 JDK。32 位實(shí)例需要 32 位的 JDK。
清單 6. SQL4301 rc=0 示例 2:在 AIX 上收到 SQL4301 rc=0 錯(cuò)誤
$ which java
/wsdb/v81/bldsupp/AIX/jdk1.4.1/bin/java
$ java -version
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1)
Classic VM (build 1.4.1, J2RE 1.4.1 IBM AIX build ca1411-20030930 (JIT enabled:
jitc))
$ db2level
DB21085I Instance "dbguest4" uses "64" bits and DB2 code release
"SQL08022" with level identifier "03030106".
Informational tokens are "DB2 v8.1.1.88", "s050422", "U800789", and FixPak "9".
Product is installed at "/usr/opt/db2_08_01".
$ db2 connect to sample
Database Connection Information
Database server = DB2/AIX64 8.2.2
SQL authorization ID = DBGUEST4
Local database alias = SAMPLE
$ db2 "call out_language(?)"
SQL4301N Java or .NET interpreter startup or communication failed, reason
code "0". SQLSTATE=58004
|
一旦使用了適合平臺(tái)的 JDK 級(jí)別,這個(gè)錯(cuò)誤就應(yīng)該消失了。
清單 7. SQL4301 rc=0 示例 2:在 AIX 上糾正 SQL4301 rc=0 錯(cuò)誤
$ db2 connect to sample
Database Connection Information
Database server = DB2/AIX64 8.2.2
SQL authorization ID = DBGUEST4
Local database alias = SAMPLE
$ db2 "call out_language(?)"
Value of output parameters
--------------------------
Parameter Name : LANGUAGE
Parameter Value : JAVA
Return Status = 0
$ which java
/wsdb/v81/bldsupp/AIX5L64/jdk1.4.1/bin/java
$ java -version
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1)
Classic VM (build 1.4.1, J2RE 1.4.1 IBM AIX 5L for PowerPC (64 bit JVM)
build ca
ix641411-20030930 (JIT enabled: jitc))
|
常用做法是檢查 db2diag.log 中的重要錯(cuò)誤消息,由此可以判斷出使用的 JDK 級(jí)別不正確。
清單 8. SQL4301 rc=0 示例 2:db2diag.log 中的相關(guān)條目
2005-10-02-18.42.36.052560-240 E226800A732 LEVEL: Error (OS)
PID : 191200 TID : 1 PROC : db2fmp
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, oper system services, sqloLoadModule, probe:130
CALLED : OS, -, dlopen
OSERR : ENOEXEC (8) "Cannot run a file that does not have a valid format."
MESSAGE : Attempt to load specified library failed.
DATA #1 : Library name or path, 55 bytes
/wsdb/v81/bldsupp/AIX/jdk1.4.1/jre/bin/classic/libjvm.a
DATA #2 : shared library load flags, PD_TYPE_LOAD_FLAGS, 4 bytes
2
DATA #3 : String, 145 bytes
0509-022 Cannot load module
/wsdb/v81/bldsupp/AIX/jdk1.4.1/jre/bin/classic/libjvm.a.
0509-124 The program is a discontinued 64-bit object file.
2005-10-02-18.42.36.053802-240 E227533A860 LEVEL: Error (OS)
PID : 191200 TID : 1 PROC : db2fmp
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, oper system services, sqloLoadModule, probe:140
CALLED : OS, -, dlopen
OSERR : ENOEXEC (8) "Cannot run a file that does not have a valid format."
MESSAGE : Attempt to load specified library augmented with object name failed.
DATA #1 : Library name or path, 65 bytes
/wsdb/v81/bldsupp/AIX/jdk1.4.1/jre/bin/classic/libjvm.a(shr_64.o)
DATA #2 : shared library load flags, PD_TYPE_LOAD_FLAGS, 4 bytes
262146
DATA #3 : String, 231 bytes
0509-022 Cannot load module
/wsdb/v81/bldsupp/AIX/jdk1.4.1/jre/bin/classic/libjvm.a(shr_64.o).
0509-153 File /wsdb/v81/bldsupp/AIX/jdk1.4.1/jre/bin/classic/libjvm.a is
not an archive or the file could not be read properly.
2005-10-02-18.42.36.058868-240 I228394A367 LEVEL: Error
PID : 191200 TID : 1 PROC : db2fmp
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, oper system services, sqloJVMstart, probe:30
MESSAGE : sqloloadmodule failed. RC:
DATA #1 : Hexdump, 4 bytes
0x0FFFFFFFFFFFC080 : 870F 009B ....
2005-10-02-18.42.36.059205-240 I228762A362 LEVEL: Error
PID : 191200 TID : 1 PROC : db2fmp
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, oper system services, sqloJAttach, probe:5
MESSAGE : JVM startup failed. RC:
DATA #1 : Hexdump, 4 bytes
0x0FFFFFFFFFFFF3E0 : FFFF EF34 ...4
2005-10-02-18.42.36.059511-240 I229125A363 LEVEL: Error
PID : 191200 TID : 1 PROC : db2fmp
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, BSU Java support, sqlejAttach, probe:10
MESSAGE : Error from sqloJAttach. RC:
DATA #1 : Hexdump, 4 bytes
0x0FFFFFFFFFFFF4A0 : FFFF EF34 ...4
2005-10-02-18.42.36.060331-240 I229489A372 LEVEL: Severe
PID : 251500 TID : 1 PROC : db2agent (SAMPLE)
INSTANCE: dbguest4 NODE : 000 DB : SAMPLE
APPHDL : 0-7 APPID: *LOCAL.dbguest4.051002224226
FUNCTION: DB2 UDB, routine_infrastructure, sqlerGetFmpThread, probe:20
RETCODE : ZRC=0xFFFFFBEE=-1042
2005-10-02-18.42.36.066498-240 I229862A314 LEVEL: Warning
PID : 124744 TID : 1 PROC : db2sysc
INSTANCE: dbguest4 NODE : 000
MESSAGE : Removing FMP from pool
DATA #1 : Hexdump, 16 bytes
0x0FFFFFFFFFFFE090 : 0000 0000 0000 0000 0002 EAE0 0002 49B8 ...I.
2005-10-02-18.44.20.194287-240 I230177A348 LEVEL: Event
PID : 120486 TID : 1 PROC : db2flacc
INSTANCE: dbguest4 NODE : 000
FUNCTION: DB2 UDB, config/install, sqlfLogUpdateCfgParam, probe:30
CHANGE : CFG DBM: "JDK_path" From: "/wsdb/v81/bldsupp/AIX/jdk1.4.1" To:
"/wsdb/v81/bldsupp/AIX5L64/jdk1.4.1"
|
SQL4301 RC=2
本文中沒(méi)有為 SQL4301 RC=2 錯(cuò)誤消息提供例子,但是這種錯(cuò)誤也值得注意。前面在討論為 Java 存儲(chǔ)過(guò)程支持設(shè)置環(huán)境時(shí)提到過(guò),Linux 和 HPUX 平臺(tái)需要額外的步驟。如果沒(méi)有執(zhí)行這些額外步驟,就會(huì)發(fā)生 SQL4301 RC=2 錯(cuò)誤。如果您使用這些平臺(tái),那么請(qǐng)確保正確地設(shè)置了環(huán)境。
SQL4301 RC=4
清單 9. SQL4301 rc=4 示例:Windows 上的 INSERT_JAVASP.java
D:\>javac INSERT_JAVASP.java
D:\>copy INSERT_JAVASP.class "C:\Program Files\IBM\SQLLIB\Function"
1 file(s) copied.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT_JAVASP (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT_JAVASP!iNSERT_JAVASP'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('A')
SQL4301N Java or .NET interpreter startup or communication failed,
reason code "4". SQLSTATE=58004
|
這個(gè)操作失敗并且顯示 SQL4301 rc=4 錯(cuò)誤消息。為什么呢?檢查 JAVA_HEAP_SZ 數(shù)據(jù)庫(kù)管理器配置參數(shù)是否足夠大,足以容納您的 Java 存儲(chǔ)過(guò)程。JAVA_HEAP_SZ 的默認(rèn)值(512 個(gè) 4KB 頁(yè))應(yīng)該足夠了,但是如果出現(xiàn)這種錯(cuò)誤,可以嘗試將這個(gè)值加倍。
關(guān)于這個(gè)參數(shù)的更多信息,請(qǐng)查閱:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/admin/r0000137.htm。
清單 10. SQL4301 rc=4 示例:數(shù)據(jù)庫(kù)管理器配置文件片段
D:\>db2 get dbm cfg
Database Manager Configuration
Node type = Enterprise Server Edition with local and remote clients
Database manager configuration release level = 0x0a00
Maximum total of files open (MAXTOTFILOP) = 16000
CPU speed (millisec/instruction) (CPUSPEED) = 9.368161e-007
Communications bandwidth (MB/sec) (COMM_BANDWIDTH) = 1.000000e 002
...
Database monitor heap size (4KB) (MON_HEAP_SZ) = 66
Java Virtual Machine heap size (4KB) (JAVA_HEAP_SZ) = 1
Audit buffer size (4KB) (AUDIT_BUF_SZ) = 0
Size of instance shared memory (4KB) (INSTANCE_MEMORY) = AUTOMATIC
Backup buffer default size (4KB) (BACKBUFSZ) = 1024
Restore buffer default size (4KB) (RESTBUFSZ) = 1024
...
|
JAVA_HEAP_SZ 為 1(4K 頁(yè))顯然不夠運(yùn)行哪怕是最簡(jiǎn)單的存儲(chǔ)過(guò)程。在大多數(shù)情況下,默認(rèn)設(shè)置 512(4K 頁(yè))應(yīng)該足夠了。在很少見的情況下,可能仍然會(huì)出現(xiàn)這個(gè)錯(cuò)誤消息,此時(shí)可以考慮將這個(gè)配置參數(shù)再加倍。
清單 11. SQL4301 rc=4 示例:更新數(shù)據(jù)庫(kù)管理器配置文件
D:\>db2 update dbm cfg using JAVA_HEAP_SZ 512
DB20000I The UPDATE DATABASE MANAGER CONFIGURATION command completed
successfully.
D:\>db2stop force
09/25/2005 14:33:16 0 0 SQL1064N DB2STOP processing was successful.
SQL1064N DB2STOP processing was successful.
D:\>db2start
09/25/2005 14:33:46 0 0 SQL1063N DB2START processing was successful.
SQL1063N DB2START processing was successful.
D:\>db2 connect to sample
Database Connection Information
Database server = DB2/NT 8.2.3
SQL authorization ID = SHAKEBS
Local database alias = SAMPLE
D:\>db2 call INSERT_JAVASP('A')
Return Status = 0
D:\>db2 "select * from CWYLAW.StoreData"
C
---
A
1 record(s) selected.
|
SQL4301 RC=-4301
清單 12. SQL4301 rc=-4301 示例:Windows 上的 INSERT_JAVASP.java
D:\>javac INSERT_JAVASP.java
D:\>copy INSERT_JAVASP.class "C:\Program Files\IBM\SQLLIB\Function"
1 file(s) copied.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT_JAVASP (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT_JAVASP!iNSERT_JAVASP'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('D')
SQL4301N Java or .NET interpreter startup or communication failed,
reason code "-4301". SQLSTATE=58004
|
這個(gè)操作失敗并且顯示 SQL4301 rc=-4301 錯(cuò)誤消息。為什么呢?檢查環(huán)境變量 CLASSPATH,確保 db2java.zip 在 CLASSPATH 中。如果 db2java.zip 不在 CLASSPATH 中,就添加它。
清單 13. SQL4301 rc=-4301 示例:修改 Windows 上的環(huán)境變量 CLASSPATH
D:>set | more
ALLUSERSPROFILE=C:\Documents and Settings\All Users
APPDATA=C:\Documents and Settings\Administrator\Application Data
CLASSPATH=.;C:\Progra~1\IBM\SQLLIB\java\db2jcc.jar;C:\Progra~1\IBM\SQLLIB\
java\sqlj.zip;C:\Progra~1\IBM\SQLLIB\java\common.jar;C:\Progra~1\IBM\SQLLIB\
java\db2jcc_license_cisuz.jar;C:\Progra~1\IBM\SQLLIB\java\db2jcc_license_cu.jar
...
D:\>set CLASSPATH=%CLASSPATH%;C:\Progra~1\IBM\SQLLIB\java\db2java.zip
|
在這個(gè)例子中,我們?cè)诿钚猩显O(shè)置 CLASSPATH。這只對(duì)您登錄進(jìn)的用戶會(huì)話有效。建議將它添加到全局環(huán)境中。在 Windows 上,可以使用 System Control Panel 來(lái)完成。在 UNIX 系統(tǒng)上,將 CLASSPATH 添加到用戶帳戶的 .profile 文件中。
清單 14. SQL4301 rc=-4301 示例:解決了 SQL4301 rc=-4301
D:\>db2 call INSERT_JAVASP('D')
Return Status = 0
D:\>db2 "select * from CWYLAW.StoreData"
C
---
D
1 record(s) selected.
|
SQL4302
SQL4302 常常意味著在 Java 存儲(chǔ)過(guò)程代碼中捕獲了一個(gè)異常,或者發(fā)生了錯(cuò)誤狀況。應(yīng)該檢查 db2diag.log。在 DIAGLEVEL 3(默認(rèn)設(shè)置)上,db2diag.log 捕獲堆棧跟蹤,甚至給出代碼中捕獲到異常處的行號(hào)。下面這個(gè)簡(jiǎn)單的例子假設(shè)編譯了 Query.java 并且將 Query.class 文件復(fù)制到了 Windows 計(jì)算機(jī)的 \sqllib\FUNCTION 目錄中。
清單 15. SQL4302 示例:Windows 上的 Query.java
1 import java.sql.*;
2
3 public class Query
4 {
5 public static void query ( int id , String[] s1 ) throws
SQLException, Exception
6 {
7 // Get connection to the database
8 Connection con =
DriverManager.getConnection("jdbc:default:connection");
9 PreparedStatement stmt = null;
10 String errorLabel = null;
11 String sql;
12
13
14 sql = "SELECT NAME FROM STAFF WHERE ID = ?";
15 stmt = con.prepareStatement( sql );
16 stmt.setInt(1, id);
17 ResultSet rs = stmt.executeQuery();
18
19 if (!rs.next()) {
20 // set errorCode to SQL0100 to indicate data not found
21 errorLabel = "SQL0100 : NO DATA FOUND, QUERY RETURNS
EMPTY RESULT SET";
22 throw new SQLException(errorLabel);
23 } else {
24 // move to first row of result set
25 s1[0] = rs.getString(1);
26 }
27
28
29 // clean up resources
30 rs.close();
31 stmt.close();
32 con.close();
33
34 }
35 }
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE CWYLAW.QUERY (IN ID INT, OUT NAME CHAR(9))
SPECIFIC QUERY
DYNAMIC RESULT SETS 0
NOT DETERMINISTIC
LANGUAGE JAVA
EXTERNAL NAME 'Query.query'
FENCED
THREADSAFE
PARAMETER STYLE JAVA
DB20000I The SQL command completed successfully.
D:\>db2 call query(5, ?)
SQL4302N Procedure or user-defined function "CWYLAW.QUERY",
specific name "QUERY" aborted with an exception "SQL0100 :
NO DATA FOUND, QUERY RETURNS EMPTY RESULT". SQLSTATE=38501
D:\>db2 call query(10, ?)
Value of output parameters
--------------------------
Parameter Name : NAME
Parameter Value : Sanders
Return Status = 0
|
SQL4302 錯(cuò)誤并不代表嚴(yán)重的錯(cuò)誤。實(shí)際上,這是一個(gè)好信號(hào)。它意味著 Java 代碼中的異常處理程序工作正常,并且捕獲到了一個(gè)異常。在下面您將看到,db2diag.log 實(shí)際上告訴您在 Query.java 的第 22 行捕獲了這個(gè)異常。在這個(gè)例子中 SQL4302 告訴我們,過(guò)程中的查詢 SELECT NAME FROM STAFF WHERE ID = 5 返回一個(gè)空的結(jié)果集。如果提供一個(gè)有效的 ID (比如 10),那么這個(gè)存儲(chǔ)過(guò)程將返回一個(gè)名稱(在本例中是 Sanders )。
清單 16. SQL4302 示例:db2diag.log 中的相關(guān)條目
2005-10-02-21.51.36.325000-240 I79282H396 LEVEL: Warning
PID : 2140 TID : 2684 PROC : db2fmp.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, BSU Java support, sqlejCallJavaRoutine_dll, probe:315
MESSAGE : Exception thrown during routine invocation:
DATA #1 : Hexdump, 4 bytes
0x01ACF5EC : D480 5501 ..U.
2005-10-02-21.51.36.335000-240 E79680H375 LEVEL: Warning
PID : 2140 TID : 2684 PROC : db2fmp.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, BSU Java support, sqlejLogException, probe:10
MESSAGE : ADM10000W A Java exception has been caught. The Java stack
traceback has been written to the db2diag.log.
2005-10-02-21.51.36.345000-240 I80057H475 LEVEL: Warning
PID : 2140 TID : 2684 PROC : db2fmp.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, BSU Java support, sqlejLogException, probe:10
DATA #1 : String, 112 bytes
java.sql.SQLException: SQL0100 : NO DATA FOUND, QUERY RETURNS EMPTY
RESULT SET at Query.query(Query.java:22)
DATA #2 : Hexdump, 4 bytes
0x01ACF424 : 0000 0000 ....
2005-10-02-21.51.36.355000-240 I80534H384 LEVEL: Warning
PID : 2140 TID : 2684 PROC : db2fmp.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, routine_infrastructure, sqlerJavaCallRoutine, probe:30
MESSAGE : Error from DB2ER CallUDF. RC:
DATA #1 : Hexdump, 4 bytes
0x01ACF97C : 32EF FFFF 2...
2005-10-02-21.51.36.365000-240 I80920H959 LEVEL: Error
PID : 3632 TID : 2840 PROC : db2bp.exe
INSTANCE: DB2 NODE : 000
APPID : *LOCAL.DB2.051003014530
FUNCTION: DB2 UDB, oper system services, sqlofica, probe:10
DATA #1 : Hexdump, 136 bytes
0x0012FC90 : 5351 4C43 4120 2020 8800 0000 32EF FFFF SQLCA ....2...
0x0012FCA0 : 4600 4357 594C 4157 2E51 5545 5259 FF51 F.CWYLAW.QUERY.Q
0x0012FCB0 : 5545 5259 FF53 514C 3031 3030 203A 204E UERY.SQL0100 : N
0x0012FCC0 : 4F20 4441 5441 2046 4F55 4E44 2C20 5155 O DATA FOUND, QU
0x0012FCD0 : 4552 5920 5245 5455 524E 5320 454D 5054 ERY RETURNS EMPT
0x0012FCE0 : 5920 5245 5355 4C54 5351 4C45 4A45 5854 Y RESULTSQLEJEXT
0x0012FCF0 : 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0012FD00 : 0000 0000 0000 0000 2020 2020 2020 2020 ........
0x0012FD10 : 2020 2033 3835 3031 38501
|
SQL4304 RC=1
清單 17. SQL4304 rc=1 示例:AIX 上的 SQL4304RC1.java
$ javac SQL4304RC1.java
$ cp SQL4304RC1.class ~/sqllib/function
$ db2 -tvf CreateSP_wrong.ddl
CREATE PROCEDURE SQL4304RC1 (IN INPUT int)
SPECIFIC SQL4304RC1
DYNAMIC RESULT SETS 1
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE DB2GENERAL
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'SQ4304RC1!abend'
DB20000I The SQL command completed successfully.
$ db2 "call SQL4304RC1(3)"
SQL4304N Java stored procedure or user-defined function "SHAKEBS.SQL4304RC1",
specific name "SQL4304RC1" could not load Java class "SQ4304RC1", reason code
"1". SQLSTATE=42724
|
這個(gè)操作失敗并且顯示 SQL4304 rc=1 錯(cuò)誤消息。為什么呢?注意,EXTERNAL NAME 子句中的類名拼寫錯(cuò)了(它應(yīng)該是 SQL4304RC1!abend,缺少了 “L”)。要糾正這個(gè)錯(cuò)誤,應(yīng)該刪除這個(gè)過(guò)程,并且在 EXTERNAL NAME 子句中采用正確的拼寫來(lái)重新創(chuàng)建它。
清單 18. SQL4304 rc=1 示例:糾正 SQL4304 rc=1 錯(cuò)誤
$ db2 drop procedure SQL4304RC1
DB20000I The SQL command completed successfully.
$ db2 -tvf CreateSP.ddl
CREATE PROCEDURE SQL4304RC1 (IN INPUT int)
SPECIFIC SQL4304RC1
DYNAMIC RESULT SETS 1
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE DB2GENERAL
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'SQL4304RC1!abend'
DB20000I The SQL command completed successfully.
$ db2 "call SQL4304RC1(3)"
Result set 1
--------------
ID NAME DEPT JOB YEARS SALARY COMM
------ --------- ------ ----- ------ --------- ---------
180 Abrahams 38 Clerk 3 12009.75 236.50
230 Lundquist 51 Clerk 3 13369.80 189.65
2 record(s) selected.
Return Status = 0
|
SQL4304 RC=2
清單 19. SQL4304 rc=2 示例:AIX 上的 SQL4304RC2.java
$ javac SQL4304RC2.java
$ cp SQL4304RC2.class ~/sqllib/function
$ db2 -tvf CreateSP_wrong.ddl
CREATE PROCEDURE SQL4304RC2 (IN INPUT int)
SPECIFIC SQL4304RC2
DYNAMIC RESULT SETS 1
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE DB2GENERAL
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'SQL4304RC2!abend'
DB20000I The SQL command completed successfully.
$ db2 "call SQL4304RC2(3)"
SQL4304N Java stored procedure or user-defined function "SHAKEBS.SQL4304RC2",
specific name "SQL4304RC2" could not load Java class "SQL4304RC2", reason code
"2". SQLSTATE=42724
|
這個(gè)操作失敗并且顯示 SQL4304 rc=2 錯(cuò)誤消息。為什么呢?因?yàn)?PARAMETER STYLE 是 DB2GENERAL,所以需要確保 Java 源代碼擴(kuò)展 COM.ibm.db2.app.StoredProc 。為了糾正這個(gè)問(wèn)題,將 extends COM.ibm.db2.app.StoredProc 添加到存儲(chǔ)過(guò)程類名的末尾。
清單 20. SQL4304 rc=2 示例:SQL4304RC2.java
1 //The simplest JAVA SP
2 import java.sql.*;
3 import COM.ibm.db2.app.*;
4
5 public class SQL4304RC2 extends COM.ibm.db2.app.StoredProc
6 {
7 public void abend (int input) throws SQLException,Exception
8 {
9 int errorCode;
10
11 try
12 {
13 // get caller's connection to the database
14 Connection con = DriverManager.getConnection("jdbc:default:connection");
15
16 String query = "SELECT * FROM STAFF where YEARS = ?";
17
18 PreparedStatement pstmt = con.prepareStatement(query);
19 ResultSet rs = null;
20 pstmt.setInt(1, input);
21 rs = pstmt.executeQuery();
22
23 }
24 catch (SQLException sqle)
25 {
26 errorCode = sqle.getErrorCode();
27 throw new SQLException( errorCode " FAILED - " sqle.getMessage());
28 }
29 }
30 }
|
代碼中的第 5 行現(xiàn)在正確地?cái)U(kuò)展類。重新對(duì)代碼進(jìn)行編譯,然后替換 sqllib/function 中的 .class 文件,并且重新執(zhí)行存儲(chǔ)過(guò)程。
注意:導(dǎo)致 SQL4304 rc=2 錯(cuò)誤消息的另一個(gè)常見錯(cuò)誤是,存儲(chǔ)過(guò)程的主方法被聲明為 “public static” 方法。PARAMETER STYLE DB2GENERAL 過(guò)程不能聲明為 “static” 方法,像以上代碼的第 7 行那樣進(jìn)行聲明才是正確的。
清單 21. SQL4304 rc=2 示例:糾正 SQL4304 rc=2 錯(cuò)誤
$ javac SQL4304RC2.java
$ cp SQL4304RC2.class ~/sqllib/function
$ db2 "call SQL4304RC2(3)"
Result set 1
--------------
ID NAME DEPT JOB YEARS SALARY COMM
------ --------- ------ ----- ------ --------- ---------
180 Abrahams 38 Clerk 3 12009.75 236.50
230 Lundquist 51 Clerk 3 13369.80 189.65
2 record(s) selected.
Return Status = 0
|
SQL4306
清單 22. SQL4306 示例:INSERT.sqlj
D:\>sqlj INSERT.sqlj
D:\>db2sqljcustomize -user cwylaw -password xxxxxxxxx -url
jdbc:db2://claw.torolab.ibm.com:50000/sample INSERT_SJProfile0
[ibm][db2][jcc][sqlj]
[ibm][db2][jcc][sqlj] Begin Customization
[ibm][db2][jcc][sqlj] Loading profile: INSERT_SJProfile0
[ibm][db2][jcc][sqlj] Customization complete for profile
INSERT_SJProfile0.ser
[ibm][db2][jcc][sqlj] Begin Bind
[ibm][db2][jcc][sqlj] Loading profile: INSERT_SJProfile0
[ibm][db2][jcc][sqlj] Driver defaults(user may override): BLOCKING ALL
VALIDATE BIND STATICREADONLY YES
[ibm][db2][jcc][sqlj] Fixed driver options: DATETIME ISO DYNAMICRULES BIND
[ibm][db2][jcc][sqlj] Binding package INSERT01 at isolation level UR
[ibm][db2][jcc][sqlj] Binding package INSERT02 at isolation level CS
[ibm][db2][jcc][sqlj] Binding package INSERT03 at isolation level RS
[ibm][db2][jcc][sqlj] Binding package INSERT04 at isolation level RR
[ibm][db2][jcc][sqlj] Bind complete for INSERT_SJProfile0
D:\>jar -cvf INSERT.jar *.class *.ser
added manifest
adding: INSERT.class(in = 1192) (out= 684)(deflated 42%)
D:\>db2 call sqlj.install_jar("file:///D:\INSERT.jar",
'INSERTJAR')
DB20000I The CALL command completed successfully.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT.INSERT'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('abc')
SQL4306N Java stored procedure or user-defined function "CWYLAW.INSERT",
specific name "INSERT" could not call Java method "INSERT",
signature "(Ljava/lang/String;)V". SQLSTATE=42724
|
為什么會(huì)產(chǎn)生這個(gè) SQL4306 錯(cuò)誤?請(qǐng)看看源代碼和 CREATE PROCEDURE 語(yǔ)句。注意,在 Java 代碼中,方法被聲明為:public static void iNSERT (String input)
注意小寫字母‘i’。
清單 23. SQL4306 示例:Windows 上的 INSERT.sqlj
//The simplest SQLJ SP
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
public class INSERT
{
public static void iNSERT (String input) throws SQLException, Exception
{
#sql { INSERT INTO CWYLAW.StoreData (c) VALUES (:input) };
}
}
|
清單 24. SQL4306 示例:INSERT 過(guò)程所需的 StoreData 表的 CREATE TABLE 語(yǔ)句
CREATE TABLE StoreData (c char(3));
|
但是,在 CREATE PROCEDURE 語(yǔ)句中,EXTERNAL NAME 被聲明為 EXTERNAL NAME 'INSERT.INSERT' 。注意大寫字母‘I’。所以,出現(xiàn) SQL4306 錯(cuò)誤的原因是源代碼中的 Java 方法名與 CREATE PROCEDURE 語(yǔ)句中的 EXTERNAL NAME 不匹配。要糾正這個(gè)問(wèn)題,就要確保 Java 方法與 CREATE PROCEDURE 語(yǔ)句中的 EXTERNAL NAME 子句精確匹配。在這個(gè)例子中,我們選擇修改 CREATE PROCEDURE 語(yǔ)句而不是修改源代碼。
清單 25. SQL4306 示例:INSERT 存儲(chǔ)過(guò)程的正確的 CREATE PROCEDURE 語(yǔ)句
CREATE PROCEDURE INSERT (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT.iNSERT'
;
|
現(xiàn)在,INSERT 過(guò)程能夠成功運(yùn)行了。
清單 26. 運(yùn)行 INSERT 過(guò)程
D:\>db2 drop procedure INSERT
DB20000I The SQL command completed successfully.
D:\>db2 call sqlj.remove_jar('INSERTJAR')
DB20000I The CALL command completed successfully.
D:\>db2 call sqlj.install_jar("file:///D:\INSERT.jar", 'INSERTJAR')
DB20000I The CALL command completed successfully.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT.iNSERT'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('abc')
Return Status = 0
D:\>db2 select * from StoreData
C
---
abc
1 record(s) selected.
|
還應(yīng)該花點(diǎn)兒時(shí)間看看類型簽名的 JVM 表示,因?yàn)檫@可以幫助您在遇到 SQL4306 錯(cuò)誤時(shí)識(shí)別出問(wèn)題。SQL4306 錯(cuò)誤的另一個(gè)常見原因是過(guò)程的參數(shù)與 Java 方法定義不匹配。在這個(gè)例子中,SQL4306 錯(cuò)誤的末尾包含一個(gè)含義有點(diǎn)兒模糊的錯(cuò)誤符號(hào):
清單 27. SQL4306 錯(cuò)誤顯示了 JVM 返回的 Java 類型
SQL4306N Java stored procedure or user-defined function "CWYLAW.INSERT",
specific name "INSERT" could not call Java method "INSERT", signature
"(Ljava/lang/String;)V". SQLSTATE=42724
|
(Ljava/lang/String;)V
實(shí)際上是 JVM 返回的 Java 類型簽名。
表 2. Java VM 類型簽名
類型簽名 |
Java 類型 |
Z |
boolean |
B |
byte |
C |
char |
S |
short |
I |
int |
J |
long |
F |
float |
D |
double |
L fully-qualified-class ; |
fully-qualified-class |
[ type |
type[] |
( arg-types ) ret-type |
method type |
所以這個(gè)錯(cuò)誤消息指出,DB2 試圖調(diào)用 Java 存儲(chǔ)過(guò)程 INSERT ,這個(gè)過(guò)程的 Java VM 類型簽名是 (Ljava/lang/String;)V ,其中 fully-qualified-class 是 java/lang/String (即,輸入?yún)?shù)是類型 String ),返回類型是 V ,代表類型 void 。這精確地匹配 Java 方法定義:
public static void iNSERT (String input)
現(xiàn)在,已經(jīng)證實(shí) Java VM 簽名是正確的,所以確定了問(wèn)題
|