Oracle開發(fā)人員 JAVA存儲過程
2024-08-29 13:29:25
供稿:網(wǎng)友
 
 
oracle開發(fā)人員 java存儲過程 
利用java存儲過程簡化數(shù)據(jù)庫操作 
作者:kuassi mensah 
利用java存儲過程溝通sql、xml、java、j2ee和web服務。 
存儲過程(stored procedure)允許將運行于數(shù)據(jù)庫層中的持久性邏輯與運行于中間層中的商務邏輯有效地分離開來。這種分離可以降低整個應用程序的復雜性,并提供其重用性、安全性、性能和可伸縮性。 
但是,妨礙存儲過程廣泛采用的一個主要障礙是不同數(shù)據(jù)庫廠商使用各種專有的、且依賴于數(shù)據(jù)庫的實現(xiàn)語言。使用基于java的存儲過程可以解決這一問題。oracle已經(jīng)實現(xiàn)了ansi標準,這些標準規(guī)定了從sql中將靜態(tài)java方法作為過程或函數(shù)進行調(diào)用的能力。這種實現(xiàn)被簡單地稱作"java存儲過程"。
在本文中,你將了解基于java的存儲過程如何幫助簡化商務邏輯、提高其性能,并擴展數(shù)據(jù)庫的功能。本文將介紹oracle如何在數(shù)據(jù)庫內(nèi)啟用基于java的存儲過程。還會介紹java存儲過程如何訪問數(shù)據(jù),以及如何創(chuàng)建基本java存儲過程。 
選擇pl/sql還是java
在考慮oracle存儲過程時,你可能會想到pl/sql。不過,從oracle8i開始,oracle已經(jīng)在數(shù)據(jù)庫中支持java,從而為存儲過程提供了不同于pl/sql的開放式和可移植的方法。我可以聽到"$64 000問題":"我如何在pl/sql和java之間做出選擇?我是否應當忘記已經(jīng)學習的所有pl/sql相關知識,而變?yōu)橐粋€java天地的新手?" 
兩種語言都適用于數(shù)據(jù)庫編程,都有自己的優(yōu)點和弱點。在決定選擇哪一種語言時,可以參考下面根據(jù)經(jīng)驗得出的通用規(guī)則: 
對于要求與sql進行無縫集成的數(shù)據(jù)庫中心來說則邏輯使用pl/sql,從而完成對數(shù)據(jù)庫對象、類型和特性的訪問。 
出于與數(shù)據(jù)庫的無關性考慮時,可以選擇java作為開放式的語言來取代pl/sql,同時也為了集成和溝通sql、xml、j2ee和web服務等各個領域。 
oralcejvm使得java可以運行在數(shù)據(jù)庫中
從oracle8i版本1(oralce8.1.5)開始,oracle便提供緊密集成的java虛擬機(jvm),jvm支持oralce的數(shù)據(jù)庫會話期結構。任何數(shù)據(jù)庫對話期都可以在第一java代碼調(diào)用時啟動一個虛擬上專用的jvm,后續(xù)的用戶可以使用這一已經(jīng)存在的支持java的會話期。事實上,所有會話共享同一jvm代碼并保持"僅靜態(tài)"的私有狀態(tài),而垃圾則收集在單個對話期空間內(nèi),從而為各個java對話期提供了和sql操作相同的對話期隔離和數(shù)據(jù)完整性能力。這里,不需要為了數(shù)據(jù)完整性而進行單獨的java支持的過程。這一基于對話期的結構提供了較小的內(nèi)存占用率,并使oraclejvm具有與oracle數(shù)據(jù)庫一樣的線性smp可伸縮性。 
創(chuàng)建java存儲過程 
要將java方法轉(zhuǎn)換為java存儲過程需要幾個步驟,包括:用loadjava實用程序?qū)ava類加載到數(shù)據(jù)庫中,利用調(diào)用規(guī)范(call spec)發(fā)布java方法,將java方法、參數(shù)類型和返回類型映射到其sql的對應部分。下面部分說明如何完成這些步驟。 
我將使用一個簡單的hello類,它有一個方法hello.world(),返回字符串"hello world":
public class hello { public static string world () { return "hello world"; } } 
loadjava 實用程序
loadjava是加載java源文件、java類文件和java資源文件的實用程序,它可以用來驗證字節(jié)碼,并將java類和jar文件布置到數(shù)據(jù)庫中。它既可以通過命令行調(diào)用,也可以通過包含于dbms_java類中的loadjava()方法調(diào)用。為了加載我們的hello.class示例,輸入:
loadjava -user scott/tiger hello.class 
從oracle9i版本2開始,loadjava允許通過為包含在被處理的類中的方法創(chuàng)建相應的call specs來自動將java類發(fā)布為存儲過程。oracle為開發(fā)、測試、調(diào)試和布置java存儲過程提供了oracle9i jdeveloper。
the resolver spec 
基于jdk的jvm在列于classpath中的目錄中查找類引用,并對其進行解析。因為oracle數(shù)據(jù)庫類存在于數(shù)據(jù)庫模式中,所以oraclejvm利用數(shù)據(jù)庫解析器(resolver)通過列于resolver spec中的模式查找并解析類引用。與classpath不同(classpath可以應用于所有的類),resover spec根據(jù)每類的情況進行應用。缺省解析器首先在加載類的模式中搜尋類,然后在公共同義詞(public synonyms)中搜索。 
 loadjava -resolve <myclass> 
你可能需要指定不同的解析器,也可以在使用loadjava時強制進行解析,從而在布置時確定可能在以后運行時發(fā)生的任何問題。 
loadjava -resolve -resolver "((* scott) (foo/bar/* others) (* public))" 
call spec和存儲過程調(diào)用 
為了從sql中調(diào)用java方法(以及從pl/sql和jdbc中調(diào)用),必須首先通過call spec發(fā)布公共靜態(tài)方法,它為sql定義方法采用的參數(shù)以及返回的sql類型。
在我們的例子中,我們將利用sql*plus連接到數(shù)據(jù)庫,并為hello.world()定義一個頂級call spec: 
sql> connect scott/tiger sql> create or replace function helloworld return varchar2 as language java name 'hello.world () return java.lang.string'; / function created. 
可以像下面這樣調(diào)用java存儲過程:
sql> variable mystring varchar2[20]; sql> call helloworld() into :mystring; call completed. sql> print mystring; mystring --------------------- hello world 
java存儲過程可以通過其call spec從以下各項中進行調(diào)用:sql dml語句(insert, update、delete、select、call、explain plan、lock table和merge)、pl/sql塊、子程序、程序包以及數(shù)據(jù)庫觸發(fā)器。call spec的美妙之處在于存儲過程實現(xiàn)可以從pl/sql轉(zhuǎn)換為java,反之亦可,這一點對于請求者是透明的。
call spec從實現(xiàn)語言中(pl/sql或java)中抽象出調(diào)用界面,因而使之能夠在原有應用程序和新的基于java/j2ee的應用程序之間共享商務邏輯。但是,在從java客戶程序調(diào)用在數(shù)據(jù)庫駐留的java類時,你可能不希望通過pl/sql包裝器(wrapper)。在以后的版本中,oracle計劃提供一種機制,它可以使開發(fā)人員略過call spec。
高級數(shù)據(jù)訪問控制 
java存儲過程可用于控制和限制對oracle數(shù)據(jù)的訪問,其方法是只允許用戶通過存儲過程管理數(shù)據(jù),而存儲過程在其調(diào)用者的權限內(nèi)執(zhí)行,而不能對表本身進行訪問。例如,你可以在特定時間內(nèi)禁止更新數(shù)據(jù),或者使管理者只具有查詢工資數(shù)據(jù)的權利,而不能進行更新,或者記錄所有的訪問并通知某一安全機構。
原有應用程序與j2ee應用程序之間的數(shù)據(jù)邏輯共享
因為原有應用程序與j2ee應用程序都通過call spec調(diào)用存儲過程,所以j2ee和非j2ee應用程序可以共享相同的數(shù)據(jù)邏輯。由于有了call spec,所以不用考慮所用的是何種實現(xiàn)語言(無論是pl/sql還是java),該數(shù)據(jù)邏輯都可以共享。 
為bmp實體bean自動生成主關鍵字
在對ejb實體bean應用bmp時,一個bean實例可以由自動生成的與新插入的數(shù)據(jù)相關聯(lián)的主關鍵字惟一確定,它是ejbcreate()的返回值??梢岳靡粋€插入相應數(shù)據(jù)的存儲過程在一個數(shù)據(jù)庫操作中檢索ejbceater()中的該值,并檢索或計算主關鍵字。作為另一種方法,也可以利用jdbc3.0的return_generated_keys特性,以一個sql語句插入該數(shù)據(jù)并檢索相應的關鍵字(或rowid)。但是,存儲過程方法在各個jdbc驅(qū)動器版本和數(shù)據(jù)庫之間更具可移植性。
可以用以下三個步驟實現(xiàn)這一模式:
創(chuàng)建一個java存儲過程,在公共genpk類中定義一個公共靜態(tài)java方法insertaccount()。此方法將插入數(shù)據(jù)、計算惟一的關鍵字(通過發(fā)出一個序列號),并返回計算出的關鍵字作為主關鍵字。 
定義call spec 
create or replace procedure insertaccount(owner in varchar, bal in number, newid out number) as language java name 'genpk.insertaccount( java.lang.string [])'; / 
在ejbcreate()內(nèi)調(diào)用存儲過程 
public accountpk ejbcreate(string ownername, int balance) throws createexception { try { callablestatement call = conn.preparecall{ "{call insertaccount(?, ?, ?)}"}; return new accountpk(accountid); } } 
為cmp實體bean定制主關鍵字查找器 
查找器方法(finder methods)用于檢索已存在的ejb實體bean實例。主關鍵字查找器使你能夠檢索惟一標識的ejb實例。對于cmp實體bean,ejb容器根據(jù)聲明描述,自動生成主關鍵字查找器findbyprimarykey()方法。但是,在某些情況下,可能需要更多的控制,例如可能需要專門的查找器,如findbystoredprockey()。在這些情況下,你可以結合使用java存儲過程和對象關系框架(如oracle9i應用服務器[oracle9ias] toplink)來實現(xiàn)定制的主關鍵字查找器方法。在將ejb查找器定義為redirect或named查找器后,toplink將生成一個sql查詢用于檢索bean實例。
數(shù)據(jù)驅(qū)動的ejb調(diào)用 
在數(shù)據(jù)驅(qū)動體系結構中,商務邏輯調(diào)用可以作為數(shù)據(jù)庫操作(如插入、更新或刪除)的結果來觸發(fā)。實現(xiàn)該數(shù)據(jù)邏輯的java存儲過程可以被聲明為數(shù)據(jù)庫觸發(fā)器,用以調(diào)用運行于中間層j2ee應用服務器的ejb。ejb的調(diào)用既可以采用j2ee1.3兼容的服務器通過interoperable inter-orb protocol(iiop)標準遠程方法調(diào)用(remote method invocation,rmi)實現(xiàn),也可以通過銷售商特定的傳輸協(xié)議(如oracle9ias/oc4j的ormi,或者通過bea weblogic的t3)用rmi來實現(xiàn)。每個應用服務器提供商在提供基于iiop的rmi,以提供互操作性的同時,都有其自己優(yōu)化的協(xié)議。oracle9ias同時支持基于iiop的rmi調(diào)用和基于ormi協(xié)議的rmi調(diào)用。 
數(shù)據(jù)驅(qū)動的消息傳送 
oracle9i數(shù)據(jù)庫嵌入了advanced queuing(aq,高級排隊),它是一種集成的、穩(wěn)定、可靠、安全、可擴展和事務處理式的消息排隊框架。oracle通過標準的java消息傳送系統(tǒng)(java messaging system,jms)api為java開發(fā)人員提供aq功能。java存儲過程可以通過jms接口調(diào)用aq操作,從而能夠?qū)崿F(xiàn)快速、在會話期內(nèi)、可擴展的、數(shù)據(jù)驅(qū)動的消息傳送。 
java存儲過程可以利用jms調(diào)用aq操作??梢杂靡韵?個步驟實現(xiàn)這一模式:
創(chuàng)建并啟動jms queue(為此,可以將以下一些操作嵌入sql腳本內(nèi)): 
execute dbms_aqadm.create_queue_table(queue_table => 'queue1', queue_payload_type => 'sys.aq$_jms_text_message', comment => 'a test queue', multiple_consumers => false, compatible => '8.1.0'); execute dbms_aqadm.create_queue( queue_name => 'queue1', queue_table => 'queue1' ); execute dbms_aqadm.start_queue(queue_name => 'queue1'); 
創(chuàng)建java存儲過程(代碼摘錄如下): 
public static void runtest(string msgbody) { try { // get database connection ora_drv = new oracledriver(); db_conn = ora_drv.defaultconnection(); // setup sender (cf online code sample) .. // create message s_msg = s_session.createtextmessage(msgbody); // send message sender.send(s_msg); s_session.commit(); // receive message r_msg = (textmessage) receiver.receive(); r_session.commit(); // output message text string body = r_msg.gettext(); system.out.println("message was '"+body+"'"); ..} } 
創(chuàng)建call spec: 
create or replace procedure jmsproc (t1 in varchar) as language java name 'jmssample.main (java.lang.string[])'; / 
調(diào)用存儲過程: 
call jmsproc('hello'); 
數(shù)據(jù)庫輔助的web發(fā)布(緩沖失效)
各應用程序結構必須面對的一個共同問題是如果可靠地將數(shù)據(jù)庫信息進行緩存,以提高整個系統(tǒng)的性能。jcache是一種即將公布的標準規(guī)范(jsr 107),它可以解決這一問題。它說明了一種對java對象臨時在內(nèi)存中進行緩存的方法,包括對象的創(chuàng)建、共享訪問、假脫機(spooling)、失效、各jvm的一致性等。它可被用于緩存jsp內(nèi)最經(jīng)常讀取的數(shù)據(jù),如產(chǎn)品目錄和價格列表。利用jcache,多數(shù)查詢的反應時間會因為有緩存的數(shù)據(jù)而加快(內(nèi)部測試表明反應時間大約快15倍)。 
為了跟蹤原始數(shù)據(jù)的所有變化,并刷新已緩存的數(shù)據(jù),java存儲過程會作為一個觸發(fā)器被附加在一個表上。這個表的任何變化都會自動調(diào)用該存儲過程,后者再調(diào)出一個已定義的jsp使jcache對象失效,該對象將其狀態(tài)映射到該數(shù)據(jù)庫表。在失效時,緊跟其后的查詢將強制緩存器根據(jù)數(shù)據(jù)庫的數(shù)據(jù)進行更新。 下面的步驟 
閱讀關于java存儲過程的更多信息
本文摘自白皮書"釋放java存儲過程的能量(unleash the power of java stored procedures)",可以在以下位置找到該白皮書:
otn.oracle.com/tech/java/java_db/pdf/
ow_30820_java_stored_proc_paper.pdf 
oracle9i數(shù)據(jù)庫第2版中的新pl/sql特性
otn.oracle.com/tech/pl_sql/pdf/
paper_30720_doc.pdf 
resolver spec
otn.oracle.com/docs/products/oracle9i/
doc_library/release2/java.920/a96659.pdf 
oraclejvm and java 2 security
otn.oracle.com/docs/products/oracle9i/
doc_library/release2/java.920/a96656.pdf 
下載代碼
練習本文中的代碼示例: 
otn.oracle.com/sample_code/tech/
java/jsp/oracle9ijspsamples.html 
了解作為web服務的存儲過程
otn.oracle.com/tech/webservices 
 
擴展數(shù)據(jù)庫的功能 
在數(shù)據(jù)庫中直接運行java代碼的一個妙處就在于要實現(xiàn)新的功能,只需要簡單地加載代碼或庫,并利用call spec制作可用于sql、pl/sql、java、j2ee和非java api的進入點(公共靜態(tài)方法)。oracle9i數(shù)據(jù)庫用戶可以很容易地擴展數(shù)據(jù)庫功能。oracle自己利用這種能力來獲得新的應用程序和工具包,如xml developer kits(xdks)。 
溝通sql、pl/sql、java、j2ee、.net和xml 
oracle xdk是用java編寫的,并將其公共方法可用作java存儲過程,從而擴展了數(shù)據(jù)庫的xml可編程能力。sql、pl/sql、java、j2ee和非java(.net)商務邏輯都能夠訪問xml分析器、xslt處理器、xpath引擎和xml sql utility(xsu)。 
xml分析器可以通過xmlparser和xmldom包進行訪問。xsu是一種java實用程序,它可以由sql查詢結果或jdbc resultset生成xml文檔,并將xml文檔中的數(shù)據(jù)寫入數(shù)據(jù)庫表或視圖中。利用xsu,xml輸出可以輸出為文本、dom樹或dts。通過dbms_xmlquery和dbms_xmlsave包,xsu即可用于pl/sql。 
結論
oracle數(shù)據(jù)庫與java vm的集成可以創(chuàng)建可移植、功能強大和與數(shù)據(jù)庫無關的數(shù)據(jù)邏輯和持續(xù)性邏輯(persistence logic)。運行于中間層的商務邏輯和運行于數(shù)據(jù)庫層的數(shù)據(jù)邏輯之間的分離提高了應用程序的可擴展性、靈活性和可維護性。