2004年5月
アプリケーション開発におけるJavaの利用は急速に拡大しています。しかしながら、既に多くのプログラム資産を所有しているユーザーにとって、すべてを一からJavaで作り直すのは無駄なことです。特にデータベース内に蓄えられたPL/SQLプログラムの資産を有効利用したいと考えるのは自然な発想です。このドキュメントでは、JavaからのPL/SQLの呼び出しと効果的なデバッグ方法を紹介します。
Java から PL/SQLプログラムを呼び出すためには、一般に以下のような手順をとります。
この手順は、ほぼパターン化された定型のスタイルですが、実際にこのようなコードを用意するのは煩雑で手間のかかる作業です。これを簡易化する方法として、Oracle JPublisher ユーティリティを使用できます。このユーティリティは、指定されたPL/SQLプログラムから、それをコールするJavaユーティリティ・クラスのコードを生成します。
JPublisher ユーティリティは、Oracleデータベースやアプリケーション・サーバーに同梱されており、コマンドラインで実行することができます(JPublisherについての詳細は 該当マニュアルを参照ください)。しかし、より簡単な方法は Oracle JDeveloper から利用することです。この場合、より対話的な方法で PL/SQL プログラムを Java で利用可能な状態にして、そのままコンパイル、実行できます。
| 注意: |
JDeveloper 10gに組み込みの JPublisher ユーティリティは、現在、SQLJ の機能を利用したコードを生成しますが、SQLJ は 2005年末でサポートが終了される予定です。JPublisher ユーティリティは、今後、SQLJ の機能を使わずに直接 JDBC を利用する Javaコードを生成できるように改良されます。
|
ここでは一つの例を使って、手順を追って紹介します。
sample パッケージに含まれるように構成してます。
TEST_EMP_PROC1 および TEST_EMP_PROC2 というプロシージャがある場合を想定して以後の話を進めています。この2つのプロシージャのソースは本ドキュメントの最後に掲載しています。
sample\TopLevel.sqljファイルが
PLSQL プロジェクトに追加されます。
作成されたソースを利用するテスト用のJavaプログラムを作成してみましょう。
mainメソッドの下など)で conn と入力。Ctrl + Enter を押す。これで、getConnection というメソッドの雛型が記述されます。

thinConn 内のホスト名やサービス名、ユーザー名やパスワードの情報(username および password)を自分の環境に合わせて変更します。
main メソッド内に以下のようなコードを追加します。
try { // 設定されたDB接続情報を使ってオブジェクトをインスタンス化 Connection conn = getConnection(); TopLevel tl = new TopLevel( conn ); // PL/SQL の TEST_EMP_PROC* に対応する Javaメソッドをコール tl.testEmpProc1( new Integer(20) ); tl.testEmpProc2( new Integer(20) ); // 接続を閉じる conn.commit(); conn.close(); } catch (SQLException e) { e.printStackTrace(); }
この TestMain を実行すると、DBセッションが確立された後、TEST_EMP_PROC1 および TEST_EMP_PROC2 プロシージャが実行されます。
JDeveloper を使用すると、データベース内のPL/SQLプログラムのコードを JDeveloper 内から参照して、その実行とデバッグを行うことができます。これについては、次の資料に記述がありますので、そちらを参照してください。
JavaからPL/SQLの呼び出しを行うアプリケーションを作成して、何か問題に直面した場合、Javaアプリケーションから正しい引数が渡されているか、PL/SQLプログラムで正しく受け取っているか、その後PL/SQLプログラムが期待通りに機能しているか、などのチェックが必要な場合があります。
これを行うためには、Javaアプリケーションのデバッグ、PL/SQLのデバッグを個々に単独で行うだけでは不十分です。Java アプリケーションのデバッグと、そこから呼び出されるPL/SQLのデバッグをシームレスに行うことが必要になります。
JDeveloper の強力なデバッガは、PL/SQLのリモート・デバッグ機能を提供します(前述の資料の「 リモートからのPL/SQLデバッグ」の章を参照)。この機能を利用すると、Java-PL/SQLのシームレス・デバッグが可能になります。
| 注意: |
PL/SQLリモート・デバッグの機能は、対象のデータベースがOracle9i Database Release2 以降の場合でのみサポートされます。
|
このデバッグ方法を行うためには、Javaアプリケーションのデバッグを行うプロジェクトと、PL/SQLのリモート・デバッグを制御するプロジェクトの2つが必要になります。

GRANT DEBUG ANY PROCEDURE TO <ユーザー名>
GRANT DEBUG CONNECT SESSION TO <ユーザー名>
例えば、先に作成した
DBMS_DEBUG_JDWP.CONNECT_TCP( ' <<JDevHostName>> ', <<Port_Number>> );
TestMain サンプル・プログラムでは、2つのPL/SQLプログラム(TEST_EMP_PROC1、
TEST_EMP_PROC2)が呼び出されますが、このコードを追加するのは最初に呼び出される
TEST_EMP_PROC1の先頭位置です。
PROCEDURE TEST_EMP_PROC1 ( dept_no INTEGER ) AS : BEGIN DBMS_DEBUG_JDWP.CONNECT_TCP( 'MyJDevHost', 6000 ); FOR empdata IN emplist LOOP :
| 注意: |
この行は、一つ前の手順で起動したデバッグ・リスナーがリスニングを開始している状態でのみ実行可能です。リスニングされていないホストやポートに対してこのコードを実行するとORA-30683エラーが発生します。
|
JDeveloper は、単なるJ2EE開発環境を越えた多くの機能を提供します。本ドキュメントによって、JDeveloper が PL/SQL と Java に対する強力な開発方法を実現可能であることがわかります。ここではシンプルなテスト用JavaプログラムからのPL/SQLの呼び出しを例にあげましたが、同じ仕組みが、Servlet などのサーバーサイドJavaコンポーネントからPL/SQLを呼ぶ場合にも適用できます。
最後に、本ドキュメントで使用したサンプル・コードを紹介しておきます。
PROCEDURE TEST_EMP_PROC1 ( dept_no INTEGER ) AS vUP INTEGER := 0; vPRE_SAL INTEGER := 100000; CURSOR emplist IS SELECT empno, sal FROM emp WHERE deptno = dept_no ORDER BY sal DESC; BEGIN FOR empdata IN emplist LOOP IF vPRE_SAL > empdata.sal THEN vUP := vUP + 100; END IF; vPRE_SAL := empdata.sal; UPDATE emp SET sal = sal + vUP WHERE empno = empdata.empno; END LOOP; END; PROCEDURE TEST_EMP_PROC2 ( dept_no INTEGER ) AS vUP INTEGER := 0; vPRE_SAL INTEGER := 100000; CURSOR emplist IS SELECT empno, sal FROM emp WHERE deptno = dept_no ORDER BY sal DESC; BEGIN FOR empdata IN emplist LOOP IF vPRE_SAL > empdata.sal THEN vUP := vUP + 100; END IF; vPRE_SAL := empdata.sal; UPDATE emp SET sal = sal - vUP WHERE empno = empdata.empno; END LOOP; END;
JPublisherによって自動で作成されます。
package sample; import java.sql.SQLException; import sqlj.runtime.ref.DefaultContext; import sqlj.runtime.ConnectionContext; import java.sql.Connection; public class TopLevel { /* connection management */ // 本ドキュメントでは省略します /* constructors */ // 本ドキュメントでは省略します public void testEmpProc1 ( Integer deptNo) throws SQLException { #sql [getConnectionContext()] { CALL TEST_EMP_PROC1( :deptNo) }; } public void testEmpProc2 ( Integer deptNo) throws SQLException { #sql [getConnectionContext()] { CALL TEST_EMP_PROC2( :deptNo) }; }
package sample; import java.sql.*; import oracle.jdbc.OracleDriver; public class TestMain { public static void main(String[] args) { TestMain testMain = new TestMain(); try { // 設定されたDB接続情報を使ってオブジェクトをインスタンス化 Connection conn = getConnection(); TopLevel tl = new TopLevel( conn ); // PL/SQL の TEST_EMP_PROC* に対応する Javaメソッドをコール tl.testEmpProc1( new Integer(20) ); tl.testEmpProc2( new Integer(20) ); // 接続を閉じる conn.commit(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { // DB接続情報は環境に合わせて変更してください String username = "scott"; String password = "tiger"; String thinConn = "jdbc:oracle:thin:@<<DBHostName>>:1521:<<serviceName>>"; Driver d = new OracleDriver(); Connection conn = DriverManager.getConnection(thinConn,username,password); conn.setAutoCommit(false); return conn; } }