北京赛车单双技巧 北京赛车pk10黑客软件 北京pk10计划免费软件 pk10前二做号工具 pk10专业预测 pk10民间高手 北京pk10挂机选号经验分享模式 pk10冠军3码倍投计划 北京赛车计划app手机版 北京赛车开奖软件 pk10最牛稳赚模式最新 pk10全天免费计划 易算北京pk10准不准 pk10赛车7码技巧 pk10八码滚雪球3期一收

將DBMS存儲過程封裝為會話EJB組件中的方法

1/5/2008來源:Java教程人氣:5032


內容:

入門
開發任務
應用方案
EJB 遠程接口
編碼封裝器方法
連接到數據庫
調用存儲過程
檢索與返回輸出
處理異常
構建客戶機應用
創建 EJB
處理返回的對象
總結
參考資料
關于作者

集成 Web 應用服務器和數據庫治理 (DBMS) 技術是很多新型商業應用的常見需求。在本文中,我們將討論該集成的一個方面:如何在會話 EnterPRise javaBeans (EJB) 組件中設計與開發封裝或調用現有 DBMS 存儲過程的方法。您應該熟悉 EJB 技術、結構化查詢語言 (SQL) 和 Java 數據庫連接 (JDBC) 的基本知識,以便充分理解本文。

假如您正致力于需要訪問或修改在 DMBS 中數據的 Web 應用程序開發,那么可能已經在向基于 EJB 的設計轉移。您可能會發現,通過使會話 EJB 組件利用 DBMS 存儲過程,可以減少編碼和維護工作,并可能提高數據訪問性能。

一些公司多年來一直在使用存儲過程(stored procedure),很大程度上是因為它們可以幫助減少網絡通信量,并提高分布式計算環境中的性能。通常,這些過程包含涉及多數據庫操作的重要業務邏輯。遠程應用程序調用這些過程,在 DMBS 服務器上執行它們所包含的 SQL 語句。當然,過程結束時,所有結果都返回給應用程序。

這些舊有存儲過程對 Web 應用通常是有用的。與其在 EJB 組件中復制這些邏輯,為什么不將這些過程作為方法封裝在會話 bean 中呢?這樣可以避免 DBMS 服務器和 EJB 組件中的冗余代碼 -- 在考慮開發、調試和維護開銷時,冗余代碼將損耗開發效率。這還可能帶來提高性能的好處。調用存儲過程可以減少 EJB 組件原本不得不發出的 SQL 語句數量,從而減少與遠程 DBMS 的通信開銷。

入門
現在明白為什么要從會話 bean 調用存儲過程了吧,下面我們看看如何開始。首先,需要使用適當的開發環境,該環境應該包括一個帶有內置 EJB 支持的 Java 開發工具,一個 Web 應用服務器和一個關系 DBMS。我的參考配置包括 VisualAge for Java 企業版 3.0.2,WebSphere application Server 高級版 3.0.2.1,以及 DB2 V7.1,所有這些都安裝在一個 Windows NT 系統上。有關如何配置該環境以支持本文所述工作的具體信息,請參閱 "Leveraging DBMS Stored Procedures through Enterprise JavaBeans"(位于參考資料中)或參考產品手冊。

有了正確的軟件環境,就可以開始了。雖然我們要討論的編碼模式可能適合于無狀態會話(stateless session) bean,但它也可使用有狀態會話(stateful session) bean 組件。但是,因為無狀態會話 bean 比有狀態會話 bean 消耗的系統資源更少,而且涉及的代碼也更少,所以通常建議使用無狀態會話 bean。

首先要考慮的設計問題是如何在存儲過程和 EJB 組件之間映射數據。存儲過程可能需要多個輸入、輸出和輸入/輸出參數,并返回一個或多個結果集(代表數據行)。除非要對不同類型的過程使用不同的編碼模式,您需要編寫 EJB 組件以便處理所有這些可能性。

處理輸入(或者輸入/輸出)參數很簡單:將存儲過程需要的每個參數映射成 EJB 組件的輸入參數。但是,處理存儲過程的輸出比較棘手。可能有多個輸出參數和多個結果集要傳回調用程序,需要將這些作為一個可序列化的對象返回,以符合 EJB 規范。可以編寫自己的類,使其可以將這些數據打包成一個對象,并在該對象中包括所有必須的元數據。(該元數據將描述對象的內部結構,以便客戶機知道如何處理。)但這需要大量工作。

假如正在使用 VisualAge for Java 和 WebSphere,那么,有個更好的選項:使用它們的數據訪問 Bean (DAB) 庫。該庫包含一些提供位于基本 JDBC 之上的函數層的類。可能會發現 com.ibm.db.CallableStatement 類非凡方便,因為它答應創建一個可序列化的對象,該對象包含所有從存儲過程返回的輸出,包括多個結果集(假如有的話)和相關元數據。還有一個好處是,該庫設計成可以支持任何支持 JDBC 的數據源,因此,它可以使 bean“與 DBMS 無關”。有了 DAB 庫,就可以用一個編碼模式在會話 EJB 組件中封裝任何存儲過程。甚至可以在 EJB 客戶機中使用一個通用的編碼模式,來處理任何從封裝器方法返回的結果。

回顧開發任務
我們來討論一下使用通用編碼模式,來集成 EJB 組件和 DBMS 存儲過程的步驟:

確定要將哪個存儲過程封裝成 EJB 方法。假如該過程不存在,則遵循 DBMS 標準過程來創建和調試。
確定要使用哪個無狀態會話 EJB 組件。假如該 EJB 不存在,則遵循 Java 開發環境的標準過程來創建和調試。
擴展 EJB 組件的遠程接口,以包括用于封裝存儲過程的新方法。
擴展 EJB 組件的實現,以包括封裝存儲過程的新方法的邏輯。連接到數據庫、調用存儲過程、處理所有結果集和處理所有異常是后面要解決的問題。
通過構建一個客戶機應用或 Servlet,來調用 EJB 組件封裝器方法,以測試所做的工作。
頭兩項是基本編程任務,您可能已經熟悉。根據所用產品的不同,個別步驟可能會略有不同,但是大多數產品都有工具來提供幫助。例如,假如正在使用 VisualAge for Java 和 DB2,則可以利用“存儲過程構建器”來完成步驟 1,以及利用 EJB 開發特性來完成步驟 2。本文將不集中講述頭兩步。但是,其余三步需要具體講解。本文將在一個實際示例的環境下討論這些步驟中的每一步。

瀏覽應用方案
假設需要構建一個應用,該應用支持一家公司的市場營銷分部,該分部維護面向金融的 Web 站點。該站點答應人們注冊為客戶,跟蹤他們的投資總額,以及在電子公告板上發表意見。另外還假設,支持該站點的數據存儲在 DB2 的表中。以下代碼樣本顯示如何創建這些表。

在 DB2 中創建樣本表的 SQL 語句

create table client (
id int not null primary key,
name varchar(30),
email varchar(30),
phone varchar(12),
regdate date,
mktg char,
constraint check1 check (mktg in (′y′, ′Y′, ′n′, ′N′))
)

create table portfolio (
id int not null,
clientID int not null references client,
ticker varchar(10) not null,
cost decimal (9,2),
qty int,
date date,
primary key (id, clientID, ticker)
)

create table boards (
msgno varchar(15) not null primary key,
subject varchar(40),
date date,
clientID int not null references client
)

該數據庫還包含一個非凡重要的存儲過程。過程 CLIENTREPORT 提供注冊站點用戶的綜合概要,包括用戶投資和他們在公告板上討論的問題。這個報告還包括客戶名稱和電子郵件地址,以便在用戶提出有關有潛在價值的附加產品或服務方面的建議時,市場營銷人員可以與這些用戶聯絡。要在會話 EJB 組件中封裝的就是這個過程。

因為此過程可能用多種語言(包括 Java 編程語言)編寫,這里就不顯示它的完整內容。不管怎么說,源代碼確實不那么重要,因為您不能假設總是可獲得它們。但是,為了告訴您存儲過程有什么內容,這里顯示了它包括的三個 SELECT 語句:

CLIENTREPORT 存儲過程中的 SQL 語句

select name, e-mail from client where id = ?
select id, ticker, cost, qty, date from portfolio where clientid = ?
select msgno, subject, date from boards where clientid = ?

問號表示,該語句將依靠運行時來自調用程序的輸入,在這種情況下,調用程序必須提供一個代表感愛好的客戶標識的有效數據值。通過這些語句,您可以猜出,存儲過程將需要一個輸入參數(用于客戶標識),返回兩個輸出參數(用于客戶名稱和電子郵件地址),并返回兩個結果集(一個包含有關客戶投資總額的數據,另一個包含有關客戶公告板發表內容的數據)。

修改 EJB 組件的遠程接口
現在我們來開始 EJB 組件代碼工作。

既然要使封裝器方法對 EJB 組件客戶機可用,我們需要擴展 bean 的遠程接口。將使用一個名為 Analysis 的無狀態會話,并包括一個 lookupClient 方法,以用于存儲過程封裝器。該方法需要一個整數作為輸入,以代表要報告的客戶標識,它返回一個 DAB CallableStatement 對象(位于 com.ibm.db.* 包中)。將把該過程返回的任何異常轉換成 RemoteExceptions(這適用于與 EJB 1.0 兼容的會話 bean)。

以下編碼示例顯示了 EJB 組件遠程接口的修改部分。

EJB 組件遠程接口

// Enterprise JavaBean Remote Interface for Analysis session bean
public interface Analysis extends javax.ejb.EJBObject {
// remote interface for our lookupClient method
com.ibm.db.CallableStatement lookupClient(java.lang.Integer clientId)
throws java.rmi.RemoteException;
. . .
}

請注重,假如使用 VisualAge EJB 組件向導,則無需對此進行手工編碼。替代方法是,在 bean 的實現類中對此方法編碼之后,通過菜單項來將該方法提升(promote)到 bean 的遠程接口,然后,將自動添加必需的代碼。

編碼存儲過程封裝器方法
現在可以集中講述 bean 實現類本身,將在該實現類中包括調用存儲過程的代碼,并將其所有輸出作為 com.ibm.db.CallableStatement 對象返回。此代碼樣本包含調用 CLIENTREPORT 存儲過程的 lookupClient(...) 方法的完整實現。將在后續章節中具體講解每個代碼塊(參考代碼中的注釋)的邏輯,以便您更好地理解如何為自己的存儲過程實現類似的方法。

連接到數據庫
讓我們更具體地查看此代碼的各部分。

在調用存儲過程之前,需要建立一個到 DBMS 的連接。有兩種方法做得到:使用 1.0 樣式的連接,或者使用 JDBC 2.0 樣式的 DataSource。在 WebSphere 環境中,通常選用后者,因為它提供連接池(connection pooling),這可以更有效地使用系統資源。出于這種原因,我們的編碼模式使用 DataSource。

除了確定要建立的連接類型之外,還應該考慮要將連接邏輯放在 bean 中的什么地方。有多個選擇:

直接放在封裝器方法(wrapper method)中
放在私有輔助方法(helper method)中
放在 ejbCreate() 方法中(并將相應的斷開邏輯放在 ejbRemove() 方法中)
這些方法的利弊超出了本文的范圍。為簡單起見,樣本代碼將所有連接/斷開邏輯直接放在方法中。

代碼塊 1 顯示了在使用 VisualAge for Java 3.0.2 和 WebSphere 3.0.2.1 時,如何使用 DataSource 進行連接。我們創建了一個散列表,在其中填充適合于 WebSphere 環境的值,然后建立一個 InitialContext。代碼的以下幾行利用該初始上下文和 Java 命名和目錄接口 (JNDI) 服務,來獲得期望的 DataSource 的索引,我們以前在 WebSphere 中用“治理控制臺”創建了該 DataSource。本例中的 DataSource 名為 LocalDB2Sample。下一步,使用該 DataSource 來獲得一個連接,并向其傳遞合適的數據庫用戶標識和口令。從連接池獲得連接之后,可以將該信息提供給 DAB DatabaseConnection 對象,來設置它所需的連接規范。最后,將 autoCommitMode 設置成 false,因為 EJB 組件負責處理事務治理服務。

測試時,在 VisualAge for Java WebSphere 測試環境中運行使用 DataSource 的 EJB 組件會很方便。有關如何在產品發行版 3.0.2 中這樣做的指示,請參閱 David Zimmerman 所著的 "Creating DataSources in the VisualAge for Java WebSphere Test Environment"(在參考資料中)。

調用存儲過程
建立了連接之后,可以集中講述如何調用存儲過程了。如封裝器方法編碼示例中的代碼塊 2 所示,首先創建一個 DAB StatementMetaData 對象,該對象中有存儲過程的規范。下一步,定義要執行的 SQL 語句。在這里將要調用 CLIENTREPORT 過程,該過程需要一個輸入參數(用于客戶標識)和兩個輸出參數(用于客戶名稱和電子郵件地址)。下一步,將參數添加到規范中。對于每個過程參數,都指定了參數名,其數據類型及其參數模式。

代碼塊 3 創建即將執行的 DAB CallableStatement 對象。CallableStatement 代表可用來執行存儲過程的 SQL。創建完對象之后,將其元數據設置成在代碼塊 2 中指定的形式。然后將 DatabaseConnection(在代碼塊 1 中創建)與該 CallableStatement 關聯。

下一個任務很簡單:需要執行 CallableStatement 對象,這將使 DBMS 運行存儲過程。但是,在這樣做之前,必須通過 EJB 客戶機應用程序,將過程的輸入參數設置成傳入方法的值。代碼塊 4 中顯示了這種邏輯。

檢索存儲過程的輸出并返回到調用程序
在封裝器方法編碼示例的代碼塊 5 中,將檢索存儲過程返回的輸出參數。想起來了嗎?這些參數代表 Web 站點客戶的名稱和電子郵件地址。但是,不需要顯式地檢索存儲過程返回的結果集。(這些結果集包含有關客戶投資總額和公告板發表信息的數據)。您可能要問:為什么會這樣呢?

某些 DBMS 要求,在獲得任何輸出參數值之前,要從存儲過程返回的結果集檢索所有需要的值。由于這種要求,在通過 getParameter() 方法進行非凡請求之前,CallableStatement bean 不從數據庫獲得任何輸出參數,因為何時從結果集檢索數據是由用戶控制的。缺省情況下,在執行存儲過程之后,將自動檢索結果集,并將其存儲在高速緩存中。但是,必須顯式檢索輸出參數,并將其存儲在高速緩存。

檢索完輸出參數之后,將 DAB CallableStatement 返回給 EJB 組件的調用程序。該對象現在包含過程返回的所有輸出(包括結果集),和幫助調用程序正確分析對象語法的適當的元數據。當我們查看調用會話 bean 封裝器方法的樣本客戶機應用程序時,將看到如何去做。

假如您熟悉 JDBC,可能會問:為什么不在此代碼塊中顯式發出 commit 語句。確實,假如使用的是 JDBC 1.0 樣式的連接,可能需要(否則,當在 "finally" 塊中關閉數據庫連接時,將逆序恢復所做的工作)。但是,使用 DataSource 并接受 WebSphere 缺省的 EJB 組件屬性 (TX_REQUIRED),WebSphere 將自動為我們的工作提供事務治理。因此,不再需要顯式的 commit 語句。

處理異常與關閉打開的資源
當然,在執行會話 bean 時可能會出錯。因此,需要提供異常處理。代碼塊 6 包括適合于與 EJB 1.0 兼容的 bean 的簡單異常處理程序。它只是捕捉碰到的任何異常,包括一個適當的錯誤消息,并將異常作為新的 RemoteException 拋回給調用程序。

另外,該代碼塊還包含一個 "finally" 塊,以確保關閉所有打開的資源。在這里,釋放任何與 CallableStatement 對象關聯的資源。下一步,除去在工作中所用的任何對連接的 DAB 引用。最后,確保關閉 WebSphere 連接。

構建客戶機應用程序
構建了 EJB 封裝器方法之后,該集中講述客戶機應用程序了。與 EJB 組件一樣,首先展示客戶機應用程序的完整代碼樣本。然后,將具體講述個別代碼塊。

這里顯示的客戶機應用程序 -- ClientAnalysis -- 使用 RMI/IIOP 與 EJB 組件通信。其工作很簡單:創建會話 bean,調用它的 lookupClient(...) 方法,處理該方法返回的 DAB CallableStatement 對象,然后除去 bean。將該應用程序編寫成處理 CallableStatement 的通用客戶機,即,假設事先不知道有關 CallableStatement 內部結構的任何信息。相反,我們嚴格依靠其中包含的元數據,來分析對象的語法,并使用其相關組件,如過程返回的輸出參數和結果集。這種方法演示了通用的編碼模式,可以在處理 CallableStatement 的任何應用程序中使用。就這樣,它補充了在無狀態會話 EJB 組件中對封裝存儲過程所用的通用編碼模式。

創建 EJB 組件并調用其封裝器方法
客戶機應用程序的代碼塊 1 以 main(...) 方法開始。它指定感愛好的客戶標識,并調用一個私有輔助方法,來獲得正在使用的會話 EJB 組件。執行完 bean 之后,調用 lookupClient(...) 方法。這是封裝 CLIENTREPORT 存儲過程并返回 DAB CallableStatement 的方法。

需要具體講述私有輔助方法 -- createEJB()。因為 EJB 組件創建工作可能會根據所用的 Web 應用程序而略有不同,所以,選擇將這個工作隔離成單獨的方法。非凡是,由于與該上下文相關的特定屬性將會改變,所以,獲得 JNDI InitialContext 的方法可能不同。

該 createEJB() 方法創建一個散列表,然后用適合于軟件環境的值填充。下一步,創建一個新的 InitialContext 對象,該對象用于通過 JNDI 服務獲得對 EJB 組件的遠程引用。因為從 JNDI 上下文返回 JNDI(這是在 IIOP 之上使用 RMI 的編碼需求),所以,限制了該遠程引用。獲得 EJB 組件宿主之后,創建一個無狀態會話 bean,然后將其返回給客戶機應用程序的 main 方法。

處理返回的對象
客戶機應用程序的代碼塊 2 處理 EJB 組件返回的 DAB CallableStatement 對象。首先定位與 CallableStatement 關聯的根元數據對象。因為 CallableStatements 可以獲得多個結果集,所以,多個 StatementMetaData 對象可以鏈接在一起,并包括在 CallableStatement 中。而鏈的根總包含描述 SQL 語句的元數據和相關參數,因此,這就是我們的開始之處。這答應我們獲得 CallableStatement 中包括的參數數目。返回的數目將包括過程的所有 IN、INOUT 和 OUT 參數。通過使用循環,可以處理所有參數并打印每個參數的相關信息,包括參數名、相應的 Java 類和模式(指明 IN、INOUT 或 OUT 模式的數字)。

下一步,查看結果集并處理它們。首先,確定 CallableStatement 對象中包括的結果集數目。通過使用循環,可以獲得每個用 DAB SelectResult 對象表示的結果集。然后,使用另一個私有輔助方法 processRS(...) 來處理結果集。processRS(...) 方法確定傳遞給 SelectResult 并包含在其中的行和列的數目。假設有一些行存在,它使用嵌套循環來打印有關所有行中的所有列的信息。該信息包括列名和它的值。

目前為止,客戶機應用程序的工作幾乎完成。代碼塊 3 除去會話 bean,打印一行表明已完成,然后終止。當然,在代碼塊 3 之后的代碼處理任何碰到的異常。在這里,只打印一個堆棧跟蹤。

總結
希望您已理解會話 EJB 組件如何利用封裝在舊有 DBMS 存儲過程中的商業邏輯。這樣做的其它可能的好處包括:減少 EJB 服務器和 DBMS 之間的網絡通信量,提高生產力,以及降低總體軟件維護成本。假如遵循本文中列出的編碼模式,則無論與過程相關的參數或結果集如何,您都可以將任何類型的存儲過程作為方法封裝在無狀態會話 bean 中。而且,您將可以使用通用編碼模式來調用任何這樣的 EJB 組件,并處理它返回的對象,而不必事先知道該對象的內部結構。

參考資料

Bontempo、Charles J. 和 Cynthia Maro Saracco 所著的 Database Management: Principles and ProdUCts, Prentice Hall, 1995, ISBN 0-13-380189-6。該書討論了數據庫治理系統的基礎,并簡述了不同商業產品中提供的功能。

Data access Beans Javadoc 描述了本文所討論的數據訪問 Bean 的 API。該書可在 VisualAge for Java 聯機文檔中獲得。在運行產品時,選擇幫助 -> 參考資料 -> IBM API -> 數據存取 Bean -> com.ibm.db 包。

Date, C. J. 所著的 An Introduction to Database Systems, Seventh Edition, Addison-Wesley, 1999, ISBN 0-20138-590-2。該書討論了數據庫治理系統的基礎,并提供有關關系數據模型的具體信息。

DB2 產品手冊

"Enterprise JavaBeans Specification" 的最新版本,可下載。

"JDBC API Specification" 的最新版本,可下載。

Monson-Haefal, Richard 所著的 Enterprise JavaBeans, O′Reilly and Associates, 1999, ISBN 1-56592-605-6。該書描述 EJB 編程基礎,并提供大量編碼示例。

Picon Joaquin 和 Patrizia Genchi、Maneesh Sahu、Martin Weiss、Alain Dessureault 所著的 Enterprise JavaBeans Development Using VisualAge for Java, IBM 紅皮書,1999 年 5 月。該紅皮書提供有關用 VisualAge for Java 開發不同種類 EJB 組件的循序漸進指示。請造訪 www.ibm.com/redbooks,并搜索 SG24-5429。

Saracco、Cynthia Maro 所著的 "Leveraging DBMS Stored Procedures through Enterprise JavaBeans," IBM 技術報告 03.723,2000 年 8 月。該報告提供十分具體地討論了本文所述的主題,還重點討論了設計問題及其利弊。可從 Database and Data Management 白皮書 或 VisualAge 開發者園地 獲得

Saracco、Cynthia Maro 所著的 Universal Database Management: A Guide to Object/Relational Technology, Morgan Kaufmann Publishers, Inc., 1998, ISBN 1-55860-519-3。該書描述了關系 DBMS 供給商已經集成到,或可能要集成到其產品中的面向對象擴展。它提供了大量 SQL 示例。

Ueno、Ken 和 Tom Alcott、Jeff Carlson、Andrew Dunshea、Hajo Kitzhofer、Yuko Hayakawa、Frank Mogus、Colin D. Wordsworth 所著的 WebSphere V3 Performance Tuning Guide,IBM 紅皮書,2000 年 3 月。該紅皮書為 WebSphere 用戶提供調整性能的技巧。請造訪 www.ibm.com/redbooks,并搜索 SG24-5657。

聯機形式的 VisualAge for Java 產品手冊(與產品一起提供),以及位于 VisualAge 開發者園地網站的產品信息。

聯機形式的 WebSphere 產品手冊(與產品一起提供),以及可從 Web 應用程序服務器 Web 站點獲得的產品信息。

White、Seth 和 Maydene Fisher、Rick Cattell、Graham Hamilton、Mark Hapner 所著的 JDBC API Tutorial And Reference, 第二版, Addison-Wesley, 1999, ISBN 0-201-43328-1。該書描述了 JDBC 2.0,并提供大量編碼示例。

Zimmerman 和 Daniel 所著的 "Creating DataSources in the VisualAge for Java WebSphere Test Environment," 通過 VisualAge 開發者園地發表的技術文章,2000 年 2 月。該文章描述使用版本 3.0.2 的 VisualAge 開發人員如何創建和訪問 DataSource。要檢索該文章,請造訪 VisualAge 開發者園地網站,并在該站點的 Articles 部分搜索 Zimmerman。
感謝
感謝 Becky Nin,在我寫這篇文章時,她為我提供了幫助。

關于作者
Cynthia M. Saracco 是 IBM 硅谷實驗室的資深軟件工程師。她在與數據庫治理、面向對象編程和 Web 技術相關的技術方面發表過兩本書和 40 多篇論文。另外,她還曾在北美、南美、歐洲和中東講述這些主題。可以通過 [email protected] 與她聯系。


pk10有什么方法平刷
北京赛车单双技巧 北京赛车pk10黑客软件 北京pk10计划免费软件 pk10前二做号工具 pk10专业预测 pk10民间高手 北京pk10挂机选号经验分享模式 pk10冠军3码倍投计划 北京赛车计划app手机版 北京赛车开奖软件 pk10最牛稳赚模式最新 pk10全天免费计划 易算北京pk10准不准 pk10赛车7码技巧 pk10八码滚雪球3期一收
浙江快乐12选5软件下载 广东十一选五预测网站 36棋牌游戏大厅下载 稳赚时时彩计划软件下载并安装 3d胆码定位 北京pk10计划官网 pk10app计划软 5144能赚钱的H5平台 河北十一选五走势图玩法