ヘッダーをスキップ
Oracle® Database SQLJ開発者ガイド
11g リリース2 (11.2)
B56282-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

11 サーバー側SQLJ

SQLJアプリケーションは、Oracle Database 11g サーバー側に格納でき、直接実行できます。SQLJアプリケーションを実行する場合、クライアント側で変換とコンパイルを行った後で、生成されたクラスとリソースをサーバー側にロードする方法と、SQLJのソース・コードをサーバー側にロードした後で、サーバーの埋込みトランスレータで変換とコンパイルを行う方法があります。

この章では、マルチスレッドや再帰的なSQLJコールなどの注意事項を含め、サーバー側でのSQLJの機能と使用方法について説明します。

内容は次のとおりです。

サーバー側SQLJの概要

SQLJコードは、Javaコードと同様に、Oracle Database 11g のストアド・プロシージャ、ストアド・ファンクションまたはトリガーでも実行できます。データ・アクセスは、SQLJランタイムのサーバー側実装とサーバー側のOracle Java Database Connectivity(JDBC)内部ドライバを介して行います。また、Oracle Database 11g の埋込みSQLJトランスレータでは、SQLJソース・ファイルをサーバーで直接変換することも可能です。

SQLJをサーバーで実行するときは、サーバー側コーディングの問題、コードの変換先およびサーバーへのロード方法について考慮する必要があります。生成された出力の名前が、サーバーで決定される方法についても注意する必要があります。クライアント側でコードを変換およびコンパイルして、クラス・ファイルとリソース・ファイルをサーバーにロードすることも、.sqljソース・ファイルをサーバーにロードして、埋込みSQLJトランスレータで自動的に変換することも可能です。

この埋込みトランスレータのユーザー・インタフェースは、クライアント側のトランスレータとは異なります。サポートされているオプションはデータベース表を使用して指定することが可能で、エラーはデータベース表に出力されます。トランスレータからの出力ファイルを開発者が意識する必要はありません。


注意:

  • Oracle Database 11g では、サーバーはJava Development Kit(JDK)1.5 Java2 Platform, Standard Edition (J2SE)環境を使用します。サーバー側のSQLJ環境は、SQLJ固有の接続Beanのサポートと「サーバーで使用するSQLJコードの作成」に記述されている関連する例外を除いて、runtime12eeライブラリを使用しているクライアント側の環境とほぼ等しいといえます。

  • このマニュアルでは、システム設定にかかわる作業を、SQLJ開発者の仕事としては位置付けていません。そのため、Oracle Database 11g Java Virtual Machine(JVM)の設定はここでは説明していません。Java関連の設定パラメータの詳細は、『Oracle Database Java開発者ガイド』を参照してください。マルチスレッド・サーバー、ディスパッチャまたはリスナーの構成に関する情報が必要な場合は、『Oracle Database Net Services管理者ガイド』を参照してください。


Oracle DatabaseのJ2EEの非サポートに関する注意事項

Oracle9i Application Server Containers for J2EE(OC4J)(新しく軽量で、使いやすく高速な、認定済のJava2 Platform, Enterprise Edition(J2EE)コンテナ)の導入によって、J2EEおよびCommon Object Request Broker Architecture(CORBA)のスタックがデータベースでサポートされなくなります。ただし、Oracle JVMはまだ存在し、データベースでのJ2SEの機能、Javaストアド・プロシージャ、JDBCおよびSQLJを提供するために機能拡張が継続して行われます。

つまり、次のテクノロジは、データベースでサポートされません。

  • Enterprise Beans(EJB)コンテナ、JavaServer Pages(JSP)コンテナおよびOracle9i Servlet Engine(OSE)で構成されるJ2EEスタック

  • Visibroker for Javaをベースにした、埋込みCORBAフレームワーク

サーブレット、JSPページ、EJBおよびCORBAのオブジェクトをOracle Databaseにデプロイすることはできません。Oracle9i リリース1(9.0.1)は、J2EEとCORBAスタックをサポートする最後のデータベース・リリースです。データベースで実行していたJ2EEアプリケーションは、OC4Jに移行することをお薦めします。

サーバーで使用するSQLJコードの作成

ほとんどの場合、ターゲットのOracle Database 11g インスタンスで使用するSQLJコードの記述方法は、クライアント側で使用するSQLJコードの記述方法と同じです。記述方法に若干の相違はありますが、これはOracle JDBCの特性や一般的なJava特性によるもので、SQLJに固有のものではありません。ただし、次のような考慮事項があります。

  • サーバー自体への暗黙的な接続が行われます。

  • 自動コミット機能など、コーディング上の注意点があります。

  • サーバー側のデフォルトの出力デバイスは、現行のトレース・ファイルになります。

  • サーバー側とクライアント側とでは、名前解決の機能が異なります。

  • SQLとJavaとでは、名前の解釈および処理の方法が異なります。

  • サーバーには、JSP、EJBまたはCORBAの機能はありません。JSPコンテナがないため、サーバー側のコードではSQLJ JSP接続Beanを使用できません。


注意:

あるサーバーからサーバー側Thinドライバを介して別のサーバーに接続するためのSQLJコードを記述する場合は、クライアント側JDBC Thinドライバを使用したアプリケーション用のコードを記述する場合と同じようにします。この項で取り上げた留意点が当てはまる場面は、ほとんどありません。

ここでは、次の項目について説明します。

サーバー側でのデータベース接続

サーバー自体でSQLJコードを実行する場合、サーバー接続の概念は異なってきます。この場合、明示的なデータベース接続はありません。デフォルトでは、サーバー側で実行されるJavaプログラムに対して、データベースへの暗黙的なチャネルが使用されます。この接続はSQLJプログラムに対して自動的に初期化されるため、自分で初期化する必要はありません。ドライバの登録や指定、接続インスタンスの作成、デフォルトの接続コンテキストの指定、#sql文の接続オブジェクトの指定、または接続の終了を行う必要はありません。


注意:

サーバー側で、次に示したようにデフォルトの接続コンテキストをNULLに設定すると、デフォルトの接続コンテキスト(サーバーへの暗黙的な接続)が再設定されます。
DefaultContext.setDefaultContext(null);

サーバー側でのコーディングの注意事項

ターゲットのサーバーでサーバー側内部ドライバを使用してコードを実行する際には、コーディング上考慮する必要がある問題が多少伴います。留意点を次に挙げます。

  • 内部ドライバで発行された結果セットは複数のコールにわたって存続するため、ファイナライザはカーソルを解放しません。このため、カーソルが不足しないように、すべてのイテレータを閉じることが特に重要です。ただし、実際に複数のコールにわたって使用される場合など、イテレータを開いたままにしておく特別の理由がある場合は別です。

  • 内部ドライバでは自動コミット機能がサポートされないため、サーバー側では自動コミット設定が無視されます。データ更新を実行または取り消すには、明示的なCOMMIT文またはROLLBACK文を使用します。

    #sql { COMMIT };
    ...
    #sql { ROLLBACK };
    

注意:

Java Transaction Service(JTS)のトランザクションなどの、XAトランザクションを使用する場合は、SQLJやJDBCのCOMMIT/ROLLBACK文またはメソッドを使用できません。

  • ISO標準コード生成の場合、JDBCコードと連係するSQLJコードを使用して、デフォルトでない接続コンテキスト・インスタンスを使用する場合は、そこにキャッシュされている文をクリーンアップするために最後に接続コンテキスト・インスタンスを終了する必要があります(同じ接続コンテキスト・インスタンスをセッション継続中に使用する場合は除く)。次に例を示します。

    DefaultContext ctx = new DefaultContext(conn); // conn is JDBC connection
    #sql [ctx] { SQL operation };
    ...
    ctx.close(sqlj.runtime.ConnectionContext.KEEP_CONNECTION);
    ...
    

    接続コンテキスト・インスタンスを終了しない場合、文ハンドルがセッション中に不足する可能性があります。また、基になるJDBC接続オブジェクトを終了しただけでは、文ハンドルは再利用されません。これは、アプリケーションをクライアントで実行するときの動作とは異なります。

    デフォルトのOracle固有コード生成の場合、文は基になるJDBC文キャッシュにキャッシュされ、自動的に再生できます。

  • Oracle固有コード生成をサーバーで実行するコードに使用する場合は、明示的なExecutionContextインスタンスを使用します。これによって、アプリケーションは、ISO標準SQLJコード生成で変換されたアプリケーションと完全に連係できるようになります。

    1つの接続に1つのスレッドを使用する(つまり、1つのOracleセッションに1つのスレッドを使用する)場合、次の例のように、静的インスタンスを1つ使用すれば十分です。

    public static ExecutionContext ec = new ExecutionContext();
    ...
    #sql [ec] { SQL operation };    // use ec for all operations
    

    1つの接続に複数のスレッドを使用する場合、実行メソッドを起動するたびに別のコンテキスト・インスタンスを使用する必要があります。


関連項目:

『Oracle Database JDBC開発者ガイドおよびリファレンス』

サーバーのデフォルトの出力デバイス

Oracle Java Virtual Machine(JVM)では、現行のトレース・ファイルがデフォルトの出力デバイスになります。サーバーで実行中のプログラムの標準出力(System.out.println()コールからの出力など)のすべてをユーザー画面に表示する場合は、次に示すように、DBMS_JAVAパッケージのSET_OUTPUT()プロシージャを実行します。バッファ・サイズはバイト単位(この場合は10,000バイト)で入力します。

sqlplus> execute dbms_java.set_output(10000);

バッファ・サイズを超過した出力は、失われます。

サーバー側で実行するコードをユーザー画面に明示的に出力されるようにする場合は、Java System.out.println()メソッドを使用するかわりに、PL/SQL DBMS_OUTPUT.PUT_LINE()プロシージャを使用します。PUT_LINE()プロシージャをオーバーロードする際には、VARCHAR2NUMBERまたはDATEのいずれかを入力とし、出力対象を指定できます。


関連項目:

『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』

サーバー側での名前解決

サーバー側でのクラスのロードと名前変換は、クライアント側での場合とは異なるパラダイムに従って行われます。これは、サーバー側とクライアント側の環境自体が異なるためです。

Oracle JVMでのJava名の解決には次が必要です。

  • クラス・リゾルバ仕様。クラス・スキーマ・オブジェクト(機能的には、クライアント側のCLASSPATHに相当)の解決の際に検索を行うスキーマのリストです。

  • リゾルバ。サーバー内で相互参照するクラス・スキーマ・オブジェクト間のマッピングを維持します。

クラス・スキーマ・オブジェクトが解決されるまで、クラスのJavaオブジェクトのインスタンス化やクラスのメソッドの実行はできません。Java名へのクラス・スキーマ・オブジェクトの外部参照のすべてがバインドされると、そのクラス・スキーマ・オブジェクトの解決が可能になります。通常、Javaプログラムのすべてのクラスは、そのコンパイルまたはロードが終わるまで解決されません。これは、通常、再帰的に互いを参照できる複数のソース・ファイルでJavaプログラムが記述されているためです。

サーバーのJavaプログラムのすべてのクラス・スキーマ・オブジェクトが解決され、解決後にいずれも変更されていない場合、プログラムは事前リンクされて実行可能な状態になります。


注意:

loadjavaユーティリティによってクラスへの参照は解決されますが、リソースへの参照は解決されません。クライアント側での変換が必要なISO標準コードの場合は、リソースをサーバーのリソース・スキーマ・オブジェクトにロードする方法に注意してください。クライアント側変換用のSQLJ -ser2classフラグを有効化すると、SQLJプロファイルはクラス・ファイル中にロードされますが、リソース・ファイルは生成されません。この逆に-ser2classを有効化しなかった場合は、プロファイルが.serリソース・ファイル中にロードされます。


関連項目:

『Oracle Database Java開発者ガイド』

SQL名とJava名

ソース名、クラス名、リソースのスキーマ・オブジェクト名などのSQL名は、Java名の場合とは異なり、グローバルではありません。Java言語仕様(JLS)では、パッケージ名にインターネットのネーミング規則を適用して、グローバルに一意なJavaプログラム名を作成するように規定されています。対照的に、SQLの完全修飾名は、現行のスキーマおよびデータベースに関連してのみ解釈されます。たとえば、1つのデータベースにSCOTT.FIZZという名前のプログラムがあるとき、同じプログラムが他のデータベースでもSCOTT.FIZZと示されるとは限りません。実際、あるデータベースのSCOTT.FIZZから、他のデータベースのSCOTT.FIZZをコールすることも可能です。

このような内在する違いから、SQL名はJava名とは異なる方法で解釈および処理する必要があります。SQL名は相対名であり、プログラムが実行されるスキーマに従って解釈されます。これは、プログラムがそのスキーマに格納されたローカル・データをバインドする方法の要となります。Java名はグローバル名であり、その名前で指定するクラスは、任意の実行サイトにロードできます。ただし、これらのクラスはプログラムのコンパイルに使用されたクラスであることを前提とします。

クライアント側でのSQLJソースの変換とコンポーネントのロード

Oracle Database 11g で使用するSQLJコードをデプロイする方法の1つは、クライアント・コンピュータ上でSQLJトランスレータを実行し、変換、コンパイルおよびプロファイルのカスタマイズ(必要な場合)を行うことです。次に、通常はJavaアーカイブ(JAR)・ファイルを使用して、生成されたクラス・ファイルとリソース・ファイル(ある場合)をサーバーにロードします。サーバー側のトランスレータがサポートするのはOracle固有コード生成のみであるため、実際には、これがサーバー側でISO標準コードを使用する唯一の方法です。

クライアント・コンピュータ上でソースを開発する場合で、SQLJトランスレータを使用できるときは、この方法をお薦めします。サーバー側でオプション設定やエラー処理を行うと手間がかかるため、クライアント・マシン上でトランスレータを実行した方が効果的です。

ISO標準コードの場合、アプリケーションをサーバーにロードするときは、変換時にSQLJ -ser2classオプションを使用することをお薦めします。このオプションを使用すると、SQLJプロファイルが.serシリアライズ・リソース・ファイルから.classファイルに変換され、名前付けが簡略化されます。ただし、.classファイルに変換されたプロファイルはそれ以上カスタマイズできないため、注意が必要です。さらにカスタマイズするには、トランスレータを再実行して、プロファイルを再生成する必要があります。

.classファイルや.serリソース・ファイルを直接またはJARファイルを使用してOracle Database 11g にロードすると、作成されるライブラリ・ユニットは、Javaクラス・スキーマ・オブジェクトおよびJavaリソース・スキーマ・オブジェクトとみなされます。SQLJプロファイル(ある場合)は、リソース・スキーマ・オブジェクト(.serファイルをロードしたときと同様にロードした場合)またはクラス・スキーマ・オブジェクト(変換時に-ser2classを有効化した場合や、.classファイルとしてロードした場合)の中にロードされます。

ここでは、次の項目について説明します。

クラスおよびリソースのサーバーへのロード

クライアント上でトランスレータを実行した後、Oracle loadjavaクライアント側ユーティリティを使用して、クラス・ファイルとリソース・ファイルをサーバーのスキーマ・オブジェクトにロードします。loadjavaコマンドラインでクラス・ファイルとリソース・ファイル(ある場合)を個別に指定するか、両ファイルをJARファイルにまとめてからコマンドラインでJARファイルを指定します。JARファイルまたはコマンドラインで指定された.classまたは.serファイル用に、個別のスキーマ・オブジェクトが作成されます。

次のように実行する例について考えてみます。

  1. ISO標準コード生成を使用して、MyIterへのイテレータ宣言があるFoo.sqljを変換しコンパイルします。

  2. Foo.sqljを変換するときに、-ser2class オプションを有効化します。

  3. 結果ファイル(Foo.classMyIter.classFoo_SJProfileKeys.classおよびFoo_SJProfile0.class)をFoo.jarにアーカイブします。

コマンドラインでloadjavaを実行します(必要なオプションも指定します)。次にデフォルトのJDBC Oracle Call Interface(OCI)ドライバを使用した例を示します。

% loadjava -user scott Foo.jar
Password: password

または、次のように元のファイルを使用することも可能です。

% loadjava -user scott Foo.class MyIter.class Foo_SJProfileKeys.class Foo_SJProfile0.class
Password: password

または

% loadjava -user scott Foo*.class MyIter.class
Password: password

ロードにJDBC Thinドライバを使用する場合は、次の例のように指定して、-thinオプションと適切なURLを指定します。

% loadjava -thin -user scott@localhost:1521/myservice Foo.jar
Password: password

注意:

  • プロファイルの変換および生成時に-codegen=iso設定を使用し、そのプロファイルを.serファイルとしてサーバーにロードすると、クライアント側でカスタマイズされていなかったプロファイルが最初にカスタマイズされます。プロファイルがすでにカスタマイズされている場合は、そのままロードされます。

  • スキーマのUSER_OBJECTSビューにアクセスすると、クラスとリソースが適切にロードされたかどうかを確認できます。


SQLJおよびJavaアプリケーションのサーバーへのロードには、loadjavaユーティリティの使用をお薦めします。ただし、次のようにSQL CREATE JAVAコマンドを使用する方法もあります。

CREATE OR REPLACE <AND RESOLVE> JAVA CLASS <NAMED name>;

CREATE OR REPLACE JAVA RESOURCE <NAMED name>;

関連項目:

『Oracle Database SQL言語リファレンス』および『Oracle Database Java開発者ガイド』

ロードされたクラスとリソース・スキーマ・オブジェクトの名前付け

ここでは、クラスやプロファイルをサーバー側にロードしたときの、この両方のスキーマ・オブジェクトの名前付けについて説明します。ただし、プロファイルが作成されるのは、ISO標準コード生成の場合のみです。

ISO標準コード生成では、アプリケーションをクライアント側で変換したときにSQLJ -ser2classオプションが有効であった場合、プロファイルは.classファイルに変換されているため、サーバーのクラス・スキーマ・オブジェクトにロードされます。-ser2classが有効になっていなかった場合、プロファイルは.serシリアライズ・リソースとして生成されるため、サーバーのリソース・スキーマ・オブジェクトにロードされます。

この後の説明では、サーバーで実行されるすべてのアプリケーションについて、デフォルトの接続コンテキスト・クラスを使用することを前提とします。このため、プロファイルは1つのみになります。

フル・ネームとショート・ネーム

サーバー側のスキーマ・オブジェクト名には、フル・ネームとショート・ネームという2つの形式があります。フル・ネームは完全修飾名であり、可能な場合は常にスキーマ・オブジェクト名として使用されます。フル・ネームが32文字以上の場合、またはフル・ネームに無効な文字やデータベース・キャラクタ・セットに変換できない文字が含まれている場合は、Oracle Database 11gでフル・ネームがショート・ネームに変換されて、スキーマ・オブジェクト名として使用されます(フル・ネームおよびショート・ネームの両方の名前、およびその変換方法は記録されています)。フル・ネームが31文字以内で、無効な文字や変換できない文字が含まれていない場合は、フル・ネームがスキーマ・オブジェクト名として使用されます。

DBMS_JAVAプロシージャでショート・ネームからフル・ネームを取得するときやその逆を実行するときの考慮事項など、スキーマ・オブジェクト名および他のファイルのネーミング規則に関する考慮事項については、『Oracle Database Java開発者ガイド』を参照してください。

ロードされたクラスのフル・ネーム

ISO標準コード生成を使用し、-ser2classフラグが有効な場合、ロードされるクラスにはプロファイル・ファイルが含まれます。.classファイルをサーバーにロードすると作成されるクラス・スキーマ・オブジェクトのフル・ネームは、元のソース・コード中のパッケージおよびクラス名によって決定されます。コマンドラインまたはJARファイルで指定するPATHは、スキーマ・オブジェクトの名前付けには影響しません。たとえば、Foo.classが、ソース・コードでx.yパッケージにあると指定されたFooクラスで構成される場合、作成されるクラス・スキーマ・オブジェクトのフル・ネームは次のようになります。

x/y/Foo

拡張子.classが削除されていることに注意してください。

Foo.sqljでイテレータMyIterが宣言されている場合、そのクラス・スキーマ・オブジェクトのフル・ネームは、次のようになります(ネストされたクラスでない場合は、それ自体のスキーマ・オブジェクトはありません)。

x/y/MyIter

さらに、ISO標準コード生成を使用している場合のフル・ネームは、次のようになります。

  • Foo.sqljの変換時にSQLJで生成される関連プロファイルキーのクラス・ファイルは、Foo_SJProfileKeys.classです。したがって、そのクラス・スキーマ・オブジェクトのフル・ネームは、次のようになります。

    x/y/Foo_SJProfileKeys
    
  • アプリケーションの変換時に-ser2classオプションが有効であった場合、プロファイルはFoo_SJProfile0.classファイルに生成されています。したがって、クラス・スキーマ・オブジェクトのフル・ネームは、次のようになります。

    x/y/Foo_SJProfile0
    

ロードされたリソースのフル・ネーム

ここで説明する内容が適用されるのは、ISO標準コード生成を使用していて、アプリケーションの変換時に-ser2classオプションが無効であった場合、またはアプリケーションで他のJavaシリアライズ・リソース(.ser)ファイルを使用する場合のみです。

リソース・スキーマ・オブジェクトとクラス・スキーマ・オブジェクトでは、名前付けの方法が異なります。リソース・スキーマ・オブジェクトの名前は、リソースの内容には依存しません。そのフル・ネームには、JARファイルやloadjavaコマンドラインに示される名前と同様に、PATHも含まれます。また、.ser拡張子は削除されません

リソース名は、実行時にリソースの場所を示すために使用されます。リソース名には必ず正しいPATHを指定することが重要です。サーバーでは、Javaがクライアント上でリソースを検索するときに使用する相対パスおよびファイル名が、リソースの正しいフル・ネームになります。

SQLJプロファイルの場合は、トランスレータの-dオプションに(パッケージ名に従って)指定したディレクトリの下のサブディレクトリが、フル・ネームになります。-dオプション(生成される.classおよび.serファイルの最上位の出力ディレクトリを指定するために使用)に/mydirを設定した場合に、アプリケーションがabc.defパッケージに含まれているときは、変換で生成される.classおよび.serファイルは/mydir/abc/defディレクトリに配置されます。

実行時には、/mydirをCLASSPATHで指定することになります。Javaではこのディレクトリの下にあるabc/defディレクトリでアプリケーション・コンポーネントが検索されます。このため、このアプリケーションをサーバーにロードするときは、コマンドラインでファイル検索箇所として指定したパスがパッケージ名をも示すように、loadjavaまたはjar-dディレクトリから実行する必要があります。次に例を示します(%はシステム・プロンプトです)。

% cd /mydir
% loadjava <...options...> abc/def/*.class abc/def/*.ser

または、次のようにJARファイルを使用することも可能です。

% cd /mydir
% jar -cvf myjar.jar abc/def/*.class abc/def/*.ser
% loadjava <...options...> myjar.jar

アプリケーションがAppで、プロファイルがApp_SJProfile0.serの場合、前述の例のいずれでも、作成されるリソース・スキーマ・オブジェクトのフル・ネームが次のように正しく設定されます。

abc/def/App_SJProfile0.ser

.serが保持されていることに注意してください。

-dには、そのディレクトリ階層に他の内容が含まれないディレクトリを設定することをお薦めします。このように設定すると、JARユーティリティを次のように実行して、アプリケーション・コンポーネントを再帰的に取得できます。

% cd /mydir
% jar -cvf myjar.jar *
% loadjava <...options...> myjar.jar

クラス・ファイルとリソース・ファイルをロードした後のアプリケーションの公開

サーバー側でJavaコードを使用する場合と同様に、サーバー側でSQLJコードを使用する場合にも、事前に最上位メソッドを公開する必要があります。公開する場合は、コール記述子の記述、データ型のマッピング、パラメータ・モードの設定を行います。


関連項目:

『Oracle Database Java開発者ガイド』

サーバー側でのクライアント・アプリケーションの実行の概要

ここでは、サーバーでクライアント・アプリケーションを実行する手順について要約します。例では、NamedIterDemoと呼ばれるデモ・アプリケーションを使用します。

  1. アプリケーション・コンポーネントとしてJARファイルを作成します。NamedIterDemoのコンポーネントとしては、SalesRec.classの他、アプリケーション・クラスやプロファイル(ある場合)などが挙げられます。

    JARファイルniter-server.jarを作成するには、次のようにします。

    % jar cvf niter-server.jar Named*.class Named*.ser SalesRec.class connect.properties
    

    .serファイルは、ISO標準コード生成の場合にのみ使用します。

  2. JARファイルをサーバーにロードします。

    loadjavaは次のように指定します。この例に示したように指定した場合、loadjavaでのファイルのロードにはOCIドライバが使用されます。-resolveオプションにより、クラス・ファイルが解決されます。

    % loadjava -oci -resolve -force -user scott niter-server.jar
    Password: password
    
  3. アプリケーション用に、SQLラッパーをサーバーに作成します。

    たとえば、次のSQL*Plusスクリプトを実行します。

    set echo on
    set serveroutput on
    set termout on
    set flush on
    
    execute dbms_java.set_output(10000);
    
    create or replace procedure SQLJ_NAMED_ITER_DEMO as language java 
    name 'NamedIterDemo.main (java.lang.String[])';
    /
    

    DBMS_JAVA.SET_OUTPUT()ルーチンでは、デフォルトの出力が、トレース・ファイルではなくユーザー画面へ戻されます。入力パラメータには、バイト単位でバッファ・サイズを指定します。

  4. ラッパーを実行します。

    次に例を示します。

    sqlplus> call SQLJ_NAMED_ITER_DEMO();
    

SQLJソースのロードとサーバーでの変換

サーバーで使用するSQLJコードを作成する場合には、ソース・コードをサーバーにロードして、サーバーで直接変換する方法もあります。この方法では、Oracle JVMの埋込みSQLJトランスレータを使用します。ここでも、クライアント・コンピュータ上でソースが作成されたことを前提とします。


注意:

サーバー側SQLJトランスレータでは、ISO標準生成コードはサポートされません。そのようなコードをサーバーで使用する場合、クライアントで変換して、個々のクラス・ファイルおよびリソースをサーバーにロードする必要があります。

サーバーへのSQLJソースのロードは、原則的にはサーバーへのJavaソースのロードと同じであり、loadjava -resolveオプションなどのコンパイル・オプションが設定されている場合は、変換が暗黙的に実行されます。.sqljソース・ファイルをOracle Database 11gに直接またはJARファイルを使用してロードすると、結果として生成されたライブラリ・ユニットにはソース・コードが格納されており、このライブラリ・ユニットはJavaソース・スキーマ・オブジェクトと呼ばれます。ソース・ファイルごとに個別のスキーマ・オブジェクトが作成されます。

変換とコンパイルが行われると、生成されたクラスに対する結果のライブラリ・ユニットは、Javaクラス・スキーマ・オブジェクトと呼ばれます。これは、クライアント側で作成された.classファイルからサーバーに直接にロードした場合と同じ名前です。クラスごとに個別のスキーマ・オブジェクトが作成されます。リソース・スキーマ・オブジェクトは、サーバーにロードしてあるプロパティ・ファイルに使用されます。

ここでは、次の項目について説明します。


関連項目:

『Oracle Database SQL言語リファレンス』および『Oracle Database Java開発者ガイド』

SQLJソース・コードのサーバーへのロード

ソースをサーバーにロードするには、(.classファイルではなく).sqljファイルに対して、Oracle loadjavaクライアント側ユーティリティを実行します。loadjava -resolveオプションを有効にして.sqljファイルをロードすると、ロード時にサーバー側の埋込みトランスレータが実行され、アプリケーションの変換およびコンパイルが行われます。それ以外の場合は、変換が行われずにソースがソース・スキーマ・オブジェクトにロードされます。ただしこの場合は、ソース中に定義されているクラスを最初に使用しようとしたときに、ソースは暗黙的に変換およびコンパイルされます。クライアント側SQLJにはこの暗黙的変換に相当するものがありません。

たとえば、loadjavaは、システム・プロンプトから次のように実行します。

% loadjava -user scott -resolve Foo.sqlj
Password: password

または、ロードにJDBC Thinドライバを使用することも可能です。

% loadjava -thin -user scott@localhost:1521/myservice -resolve Foo.sqlj
Password: password

いずれの方法でも、ソース・スキーマ・オブジェクトに加えて、適切なクラス・スキーマ・オブジェクトが作成されます。

ただし、loadjavaを実行する際は、事前にSQLJオプションを正しく設定する必要があります。エンコーディングの設定は、サーバー側SQLJ encodingオプションではなく、次のようにloadjavaのコマンドラインで指定できることに注意してください。

% loadjava -user scott -resolve -encoding SJIS Foo.sqlj
Password: password

実際のユーティリティを実行するloadjavaスクリプトの格納場所は、ORACLE_HOME ディレクトリのbinサブディレクトリです。このディレクトリは、Oracleをインストールすると自動的に作成されます。


注意:

  • JARファイルの処理では、loadjavaによって最初に.sqljファイル、.javaファイルおよび.classファイルが処理されます。次に、セカンド・パスが作成され、他のすべてがJavaリソース・ファイルとして処理されます。

  • .sqljファイルは、同じ.sqljファイルの処理で生成された.classファイルとともにロードすることはできません。このようにロードすると、サーバーで生成中のクラスやプロファイルと同じクラスに対してサーバーがロードを試みることになるため、競合が発生します。

  • 複数の.sqljファイルをJARファイルに入れて、JARファイルをloadjavaに指定できます。

  • スキーマのUSER_OBJECTSビューにアクセスすると、クラスが適切にロードされていることを確認できます。


SQLJおよびJavaアプリケーションのサーバーへのロードには、loadjavaユーティリティの使用をお薦めします。ただし、次のようにSQL CREATE JAVAコマンドを使用する方法もあります。

CREATE OR REPLACE <AND COMPILE> JAVA SOURCE <NAMED srcname> <AS loadname>;

.sqljファイルにAND COMPILEを指定すると、その時点でのソースが変換およびコンパイルされ、ソース・スキーマ・オブジェクトの他に、必要に応じてクラス・スキーマ・オブジェクトが作成されます。それ以外の場合は、変換やコンパイルが行われません。この場合、ソース・スキーマ・オブジェクトのみが作成されます。ただし、後者の場合は、ソース内のクラスを最初に使用しようとしたときに、ソースが暗黙的に変換およびコンパイルされます


注意:

初めてソース・ファイルをロードすると、定義済クラスの確認など、ソース・コードのチェックが行われます。このときにエラーが検出されると、ロードが失敗します。

サーバー側の埋込みトランスレータでサポートされるオプション

サーバー側SQLJのトランスレータでは、次のオプションを使用できます。

  • encoding

  • online

  • debug

ここでは、サーバー側SQLJでの固定した設定を説明してから、これらのオプションについて説明します。loadjavaユーティリティとその-resolveオプションについても説明します。

サーバー側SQLJトランスレータでの固定の設定

クライアント側のSQLJトランスレータのオプションによってサポートされる次の設定は、サーバー側トランスレータでは固定です。

  • サーバーでは、オンライン・セマンティクス・チェックとオフライン解析の両方がデフォルトで有効であり、これはクライアントでのデフォルトの-parse=both設定に相当します。この設定をオーバーライドして、オンライン・セマンティクス・チェックをonlineオプションで無効にすることはできますが、オフライン解析を無効にすることはできません。

  • サーバー側では、Oracle固有コード生成が使用されます。これは、クライアント側のデフォルトの-codegen=oracle設定に相当します。この設定は固定です。

  • サーバー側での変換時に生成されたクラス・スキーマ・オブジェクトは、SQLJソース・コードをマッピング先とする行番号を自動的に参照します。クライアント側での変換時に-linemapオプションを有効化すると、サーバー側と同様の自動参照が行われます。

encodingオプション

このオプションには、サーバー側にロードするときのソース・コードの解釈に使用するエンコーディングを指定します。encodingオプションは、ソースのロード時にコンパイルの有無にかかわらず、使用されます。また、loadjavaを使用してSQLJアプリケーションをサーバー側にロードする別の方法としては、loadjavaコマンドラインでエンコーディングを指定する方法もあります。loadjavaコマンドラインで設定された文字エンコーディングは、このencodingオプションに優先します。


注意:

このオプションまたはloadjavaで文字エンコーディングが指定されていない場合は、loadjavaを実行したクライアントのfile.encodingで指定された文字エンコーディングが使用されます。

onlineオプション

onlineオプションにtrue(デフォルト値)を設定すると、オンライン・セマンティクス・チェックが有効になります。セマンティクス・チェックは、ソースがロードされたスキーマに対して行われます。クライアント側でのオンライン・チェックでは、基本スキーマの指定は不要です。onlineオプションをfalseに設定すると、オフラインでチェックが行われます。

いずれの場合も、デフォルトのチェッカはoracle.sqlj.checker.OracleCheckerです。このチェッカにより、使用するJDBCドライバのバージョンとOracleのバージョンに応じてチェッカが選択されます。

onlineオプションは、ソースの変換およびコンパイル時に使用されます。loadjava -resolveオプションを有効にしてこれをロードすると、即座に実行されます。それ以外の場合は、ソースで定義されたクラスを最初に使用しようとしたときに実行されます(変換およびコンパイルは暗黙的に行われます)。


注意:

サーバー側とクライアント側とでは、onlineオプションの使用方法が異なります。サーバー側でonlineオプション使用した場合、デフォルトのチェッカでのオンライン・チェックを有効にするフラグとしてのみ機能します。一方、クライアント側では、使用するチェッカを-onlineオプションで指定できますが、別途-userオプションでオンライン・チェックを有効にする必要があります。

debugオプション

このオプションにtrueを設定すると、.sqljまたは.javaソース・ファイルがサーバーでコンパイルされるときに、サーバー側のJavaコンパイラがデバッグ情報を出力します。これは、クライアント上で標準のjavacコンパイラを実行するときに、-gオプションを使用するのに相当します。

loadjava -resolveオプションを使用した場合、ロード中にソースがコンパイルされます。.sqljファイルの場合は、SQLJ変換の直後に実行されます。-resolveオプションを使用しない場合は、ソースで定義されたクラスを最初に使用しようとしたときに暗黙的な変換およびコンパイルが実行されます。

サーバーでのSQLJオプションの設定

サーバーでSQLJトランスレータを実行するときは、コマンドラインもプロパティ・ファイルも存在しません。トランスレータやコンパイラのオプションについての情報は、JAVA$OPTIONSという表の各スキーマに保持されます。この表のオプションを操作するには、DBMS_JAVAパッケージの次のファンクションおよびプロシージャを使用します。

  • DBMS_JAVA.GET_COMPILER_OPTION()

  • DBMS_JAVA.SET_COMPILER_OPTION()

  • DBMS_JAVA.RESET_COMPILER_OPTION()

個々のパッケージやソースに対して個別のオプションを指定するには、set_compiler_option()を使用します。次を入力パラメータとして指定し、各パラメータは一重引用符で囲みます。

  • パッケージ名(ドット区切りの名前)またはソース名

    ショート・ネームではなくフル・ネームで指定します。パッケージ名を指定した場合、そのパッケージとサブパッケージのすべてのソースに、そのオプション設定が適用されます。ただし、特定のサブパッケージやソースに対して設定をオーバーライドした場合を除きます。

  • オプション名

  • オプション設定

SQL*Plusを使用して、DBMS_JAVAルーチンを実行します。

sqlplus> execute dbms_java.set_compiler_option('x.y', 'online', 'true');
sqlplus> execute dbms_java.set_compiler_option('x.y.Create', 'online', 'false');

これら2つのコマンドで、x.yパッケージ内のすべてのソースに対するオンライン・チェックが有効になります。次に、Createソースのオンライン・チェックを無効し、Createソースに対してチェックが行われないようにします。

同様に、次のように指定して、x.yパッケージのエンコーディングをSJISに設定します。

sqlplus> execute dbms_java.set_compiler_option('x.y', 'encoding', 'SJIS');

サーバー側オプションについての注意事項

次の点に注意してください。

  • スキーマ・オブジェクト名ではスラッシュ構文(パッケージ名としてabc/defなど)を使用しますが、パッケージ名やソース名のset_compiler_option()パラメータはドット区切りの名前(パッケージ名としてabc.defなど)を使用します。

  • パッケージ名を指定するときは、サブパッケージにもオプションが適用されることに注意してください。a.b.MyPackageの設定では、次の形式の名前の付いたソース・スキーマ・オブジェクトすべてに対して、オプションが設定されます。

    a/b/MyPackage/subpackage/... 
    
  • パッケージ名として''(スペースを挿入せずに一重引用符2つ)を指定した場合、ルートおよびすべてのサブパッケージに対してオプションが適用されます。結果的に、スキーマ内のすべてのパッケージにオプションが適用されることになります。

ロードされたソース、生成されたクラスおよびリソース・スキーマ・オブジェクトの名前付け

-resolveオプションを有効にしてloadjava.sqljファイルに使用するときなど、サーバー側のSQLトランスレータを使用する場合、基本的には、クライアント側で生成される内容と同じものが生成されます。出力には、ソース中に定義した各クラスのコンパイル済クラスおよび各イテレータや接続コンテキスト・クラスのコンパイル済クラスが含まれます。

このため、loadjava.sqljファイルをサーバーにロードして、変換およびコンパイルを行うと、次に示した各スキーマ・オブジェクトが作成されます

  • 元のソース・コード用のソース・スキーマ・オブジェクト

  • ソースで定義したすべてのクラス用のクラス・スキーマ・オブジェクト

  • ソースで定義した各イテレータまたは接続コンテキスト・クラス用のクラス・スキーマ・オブジェクト

    ただし、ユーザー定義型に型マップを指定するためでない場合は、サーバーで実行するコードに接続コンテキスト・クラスを宣言する必要はありません。

これらのスキーマ・オブジェクトのフル・ネームは、後述の方法で決定されます。作成されるスキーマ・オブジェクトとその名前を出力するには、loadjava -verboseオプションを指定します。

ソースのフル・ネーム

ソース・ファイルをサーバーにロードすると、変換やコンパイルが行われるかどうかにかかわらず、ソース・スキーマ・オブジェクトが作成されます。このスキーマ・オブジェクトのフル・ネームは、ソース・コード中のパッケージ名とクラス名によって決定されます。コマンドラインでloadjavaに対して指定するPATHは、スキーマ・オブジェクトの名前付けには影響しません。

たとえば、Foo.sqljx.yパッケージ内のFooクラスを定義し、他のクラスを定義または宣言しない場合、作成されるソース・スキーマ・オブジェクトのフル・ネームは次のようになります。

x/y/Foo

拡張子.sqljが削除されていることに注意してください。

クラスを追加定義したり、イテレータ・クラスや接続コンテキスト・クラスを宣言した場合、ソース・スキーマ・オブジェクトの名前は、最初に出現したPublicクラス定義またはクラス宣言に従って付けられ、Publicクラスがないときは、最初のクラス定義に従って付けられます。サーバー側では、1つのソースの中に複数のPublicクラスを定義することも可能です。

前の例と同じx.yパッケージ中のFoo.sqljに、まずPublicクラスBarを、次にクラスFooを定義したとします。このBarの定義の前にpublicイテレータ・クラスまたは接続コンテキスト・クラスを宣言しなかった場合には、作成されるソース・スキーマ・オブジェクトのフル・ネームは次のようになります。

x/y/Bar

ただし、BarクラスとFooクラスの定義の前に、publicイテレータ・クラスMyIterが宣言されている場合、作成されるソース・スキーマ・オブジェクトのフル・ネームは次のようになります。

x/y/MyIter

生成されたクラスのフル・ネーム

クラス・スキーマ・オブジェクトは、ソース中に定義されているクラス、宣言済イテレータおよびプロファイルキー・クラスのそれぞれに対して生成されます。クラス・スキーマ・オブジェクトは、ソース・コードのクラス名およびパッケージ名に基づいて名前付けされます。

ここでも、前述の「ソースのフル・ネーム」の例を使用します。ソース・コード中にx.yパッケージを指定し、最初にPublicクラスBar、次にクラスFooを定義した後で、publicイテレータ・クラスMyIterを宣言したとします。定義および宣言されたクラスのクラス・スキーマ・オブジェクトには、次のようにフル・ネームが付けられます。

x/y/Bar
x/y/Foo
x/y/MyIter

.classが付けられていないことに注意してください。


注意:

ソース名は、最初に定義されているPublicクラスの名前と同じにするか、Publicクラスが未定義の場合は、最初に定義されているクラスの名前と同じにすることをお薦めします。このようにすると、クライアント側とサーバー側で違う動作をすることを回避できます。

元のソース・ファイルの名前や、ソースのサーバーへのロード時に指定するPATHは、生成されるクラスの名前付けには影響しません。コードで内部クラスや無名クラスを定義する場合、これらのクラスは標準のjavacコンパイラのネーミング規則に従って名前付けされます。

サーバー側埋込みトランスレータからのエラー出力

サーバー側のSQLJエラー処理は、サーバー側での一般的なJavaエラー処理と同様に行われます。SQLJエラーは、ユーザー・スキーマのUSER_ERRORS表に出力されます。この表のTEXT列からSELECTを行うと、特定のエラー・メッセージを取得できます。

ただし、SQLJソースのロードにloadjavaを使用する場合は、loadjavaによってサーバー側トランスレータからのエラー・メッセージのキャプチャおよび書込みが行われます。

情報メッセージや非表示にできる警告は、サーバー側トランスレータで出力しないようにできます。これは、クライアント側トランスレータで-warn=noportable,noverbose(デフォルト)が設定された場合と同じです。

ソース・ファイルをロードした後の、アプリケーションの公開

サーバー側でJavaコードを使用する場合と同様に、サーバー側でSQLJコードを使用する場合にも、事前に最上位メソッドを公開する必要があります。公開する場合は、コール記述子の記述、データ型のマッピング、パラメータ・モードの設定を行います。詳細は、『Oracle Database Java開発者ガイド』を参照してください。

Javaスキーマ・オブジェクトの削除

loadjavaユーティリティを補足するために、Javaソース、クラスおよびリソース・スキーマ・オブジェクトを削除するdropjavaユーティリティが提供されています。loadjavaを使用してサーバーにロードしたスキーマ・オブジェクトを削除する場合は、必ずdropjavaを使用することをお薦めします。

dropjavaユーティリティでは、コマンドラインのファイル名とJARファイルの内容がスキーマ・オブジェクト名に変換され、スキーマ・オブジェクトが削除されます。.sqlj.java.class.serおよび.jarの各ファイルは、任意の順序でコマンドラインに指定できます。

Javaスキーマ・オブジェクトは、必ず最初にロードしたときと同じ方法で削除することをお薦めします。.sqljソース・ファイルをロードしてからサーバー側で変換した場合は、同じソース・ファイルに対してdropjavaを実行します。クライアント側で変換を行ってからクラスとリソースを直接ロードした場合は、同じクラスとリソースに対してdropjavaを実行します。

たとえば、Foo.sqljに対してloadjavaを実行した場合は、次のように同じファイル名を指定してdropjavaを実行します。

% dropjava -user scott/password Foo.sqlj

プログラムをクライアント側で変換してから、生成されたコンポーネントを含むJARファイルでロードした場合は、同じJARファイル名を使用してプログラムを削除します。

% dropjava -user scott/password Foo.jar

プログラムをクライアント側で変換してから、生成されたコンポーネントをloadjavaコマンドラインでロードした場合は、次のようにdropjavaコマンドラインで削除します(-codegen=oracleで、イテレータ・クラスがないことを想定しています)。

% dropjava -user scott/password Foo*.class

関連項目:

『Oracle Database Java開発者ガイド』

サーバー側のその他の考慮事項

ここでは、サーバーでのJavaマルチスレッドと再帰的SQLJコールについて説明します。次の項目について説明します。

サーバーでのJavaマルチスレッド

Javaマルチスレッドを使用するプログラムは、変更を加えなくてもOracle Database 11g で実行できます。ただし、クライアント側プログラムがマルチスレッドの使用によりスループットが向上するのに対して、サーバー側でJavaマルチスレッド・コードが実行される場合はそのようなメリットがありません。マルチスレッド・アプリケーションをサーバーに移植する場合は、次に示すOracle JVMとクライアント側JVMとのマルチスレッド機能の相違を考慮してください。

  • サーバー内のスレッドは、同時処理ではなく順次処理されます。

  • サーバーでは、1つのコール内のスレッドは、そのコールの終わりに消滅します。

  • サーバー内のスレッドは、プリエンプティブにスケジュールされません。1つのスレッドが無限ループに入った場合、他のスレッドは実行できません。

Oracle Database 11g のJavaマルチスレッドを、一般的なOracleサーバーのマルチスレッドと混同しないでください。後者の場合はOracleの同時セッションであり、Javaマルチスレッドではありません。サーバーでは、多くのユーザーが自身のセッションで同時に実行することにより、拡張性とスループットが得られます。スループットを最大にするためのJavaの実行スケジューリング(1セッション内のコールごとなど)は、JavaではなくOracle Database 11g で行われます。

サーバーでの再帰的SQLJコール

SQLJでは通常、複数のSQLJ文で同じ実行コンテキスト・インスタンスを同時に使用することはできません。つまり、すでに使用されている実行コンテキスト・インスタンスの使用を試みた文は、前の文が完了するまでブロックされます。

ただし、この機能は、クライアント上よりも、サーバー上であまり望ましくありません。その理由は、異なるストアド・プロシージャまたはストアド・ファンクションは、通常であればすべてデフォルトの実行コンテキスト・インスタンスを使用しますが、再帰的な状況においては、誤ってこの同じ実行コンテキスト・インスタンスを同時に使用しようとする可能性があるためです。たとえば、あるストアド・プロシージャがSQLJ文を使用して、SQLJ文を使用する別のストアド・プロシージャをコールする可能性があります。これらのストアド・プロシージャを最初に作成する時点では、このような状況がいつ発生するかを把握できないため、特定の実行コンテキスト・インスタンスをSQLJ文のいずれかに対して指定することは疑問です。

この状況に対処するため、SQLJでは、再帰的コールによってこのような状況が生じた場合に、複数のSQLJ文が同じ実行コンテキスト・インスタンスを同時に使用できるようになっています。

ここでは、再帰的な状況の例を考えて、実行コンテキスト・インスタンスのステータス情報がどのようになるかを説明します。すべての文で、デフォルトの接続コンテキスト・インスタンスとそのデフォルトの実行コンテキスト・インスタンスが使用されると想定します。ストアド・プロシージャproc1が持つSQLJ文が、同じくSQLJ文を持つストアド・プロシージャproc2をコールする場合、proc2内の各文は、proc1のプロシージャ・コールが使用しているときに同じ実行コンテキスト・インスタンスを使用します。

proc2の各SQLJ文によって、その文のステータス情報が実行コンテキスト・インスタンスに書き込まれるため、必要な場合は、各文の完了後にその情報を取得することができます。proc2をコールするproc1の文からステータス情報が実行コンテキスト・インスタンスに書き込まれるのは、proc2の実行が終了し、プログラム・フローがproc1に戻り、proc2をコールしたproc1内の操作が完了した後です。

再帰的な状況でも実行コンテキストのステータス情報が正しく処理されるように、実行コンテキスト・メソッドは、SQL操作が完了した後にステータス情報を更新するように定義されています。


注意:

  • サーバー側で実行されるコードの中に、実行コンテキスト・ステータスや制御メソッドを使用する計画を立てるたびに、必要に応じて別個の実行コンテキスト・インスタンスを使用することをお薦めします。

  • 前述の例で別個の実行コンテキスト・インスタンスを使用せず、しかも制御パラメータを変更するためにproc2から実行コンテキスト・インスタンスへのメソッドをコールした場合、それ以降にproc1で実行される操作に影響します。

  • バッチ更新は、再帰的コールでは使用できません。デフォルトでは、バッチ処理(有効化してある場合)を実行できるのは、最上位プロシージャのみに限定されています。こうした制限を免れるには、実行コンテキスト・インスタンスを明示的に使用する必要があります。


サーバーでのコードの実行状況の確認

作成したコードが実際にサーバー側で実行可能かどうかを確認する場合、java.lang.Systemクラスのstatic getProperty()メソッドを使用してoracle.server.versionのJavaプロパティを取得する方法が便利です。このプロパティにバージョン番号が指定されている場合、コードはサーバーで実行されます。このバージョン番号がNULLの場合、Oracleサーバーではコードが実行されません。次にその例を示します。

...
if (System.getProperty("oracle.server.version") != null 
{
   // (running in server)
}
...

注意:

サーバー側でgetProperties()メソッドは使用しないでください。セキュリティ例外の原因となります。