SQLJアプリケーションは、Oracle Database 11g サーバー側に格納でき、直接実行できます。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の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に移行することをお薦めします。
ほとんどの場合、ターゲットの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()
プロシージャをオーバーロードする際には、VARCHAR2
、NUMBER
または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名の場合とは異なり、グローバルではありません。Java言語仕様(JLS)では、パッケージ名にインターネットのネーミング規則を適用して、グローバルに一意なJavaプログラム名を作成するように規定されています。対照的に、SQLの完全修飾名は、現行のスキーマおよびデータベースに関連してのみ解釈されます。たとえば、1つのデータベースにSCOTT.FIZZ
という名前のプログラムがあるとき、同じプログラムが他のデータベースでもSCOTT.FIZZ
と示されるとは限りません。実際、あるデータベースのSCOTT.FIZZ
から、他のデータベースのSCOTT.FIZZ
をコールすることも可能です。
このような内在する違いから、SQL名はJava名とは異なる方法で解釈および処理する必要があります。SQL名は相対名であり、プログラムが実行されるスキーマに従って解釈されます。これは、プログラムがそのスキーマに格納されたローカル・データをバインドする方法の要となります。Java名はグローバル名であり、その名前で指定するクラスは、任意の実行サイトにロードできます。ただし、これらのクラスはプログラムのコンパイルに使用されたクラスであることを前提とします。
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
ファイル用に、個別のスキーマ・オブジェクトが作成されます。
次のように実行する例について考えてみます。
ISO標準コード生成を使用して、MyIter
へのイテレータ宣言があるFoo.sqlj
を変換しコンパイルします。
Foo.sqlj
を変換するときに、-ser2class
オプションを有効化します。
結果ファイル(Foo.class
、MyIter.class
、Foo_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
注意:
|
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
と呼ばれるデモ・アプリケーションを使用します。
アプリケーション・コンポーネントとしてJARファイルを作成します。NamedIterDemo
のコンポーネントとしては、SalesRec.class
の他、アプリケーション・クラスやプロファイル(ある場合)などが挙げられます。
JARファイルniter-server.jar
を作成するには、次のようにします。
% jar cvf niter-server.jar Named*.class Named*.ser SalesRec.class connect.properties
.ser
ファイルは、ISO標準コード生成の場合にのみ使用します。
JARファイルをサーバーにロードします。
loadjava
は次のように指定します。この例に示したように指定した場合、loadjava
でのファイルのロードにはOCIドライバが使用されます。-resolve
オプションにより、クラス・ファイルが解決されます。
% loadjava -oci -resolve -force -user scott niter-server.jar
Password: password
アプリケーション用に、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()
ルーチンでは、デフォルトの出力が、トレース・ファイルではなくユーザー画面へ戻されます。入力パラメータには、バイト単位でバッファ・サイズを指定します。
ラッパーを実行します。
次に例を示します。
sqlplus> call SQLJ_NAMED_ITER_DEMO();
サーバーで使用するSQLJコードを作成する場合には、ソース・コードをサーバーにロードして、サーバーで直接変換する方法もあります。この方法では、Oracle JVMの埋込みSQLJトランスレータを使用します。ここでも、クライアント・コンピュータ上でソースが作成されたことを前提とします。
注意: サーバー側SQLJトランスレータでは、ISO標準生成コードはサポートされません。そのようなコードをサーバーで使用する場合、クライアントで変換して、個々のクラス・ファイルおよびリソースをサーバーにロードする必要があります。 |
サーバーへのSQLJソースのロードは、原則的にはサーバーへのJavaソースのロードと同じであり、loadjava -resolve
オプションなどのコンパイル・オプションが設定されている場合は、変換が暗黙的に実行されます。.sqlj
ソース・ファイルをOracle Database 11gに直接またはJARファイルを使用してロードすると、結果として生成されたライブラリ・ユニットにはソース・コードが格納されており、このライブラリ・ユニットはJavaソース・スキーマ・オブジェクトと呼ばれます。ソース・ファイルごとに個別のスキーマ・オブジェクトが作成されます。
変換とコンパイルが行われると、生成されたクラスに対する結果のライブラリ・ユニットは、Javaクラス・スキーマ・オブジェクトと呼ばれます。これは、クライアント側で作成された.class
ファイルからサーバーに直接にロードした場合と同じ名前です。クラスごとに個別のスキーマ・オブジェクトが作成されます。リソース・スキーマ・オブジェクトは、サーバーにロードしてあるプロパティ・ファイルに使用されます。
ここでは、次の項目について説明します。
関連項目: 『Oracle Database SQL言語リファレンス』および『Oracle Database Java開発者ガイド』 |
ソースをサーバーにロードするには、(.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をインストールすると自動的に作成されます。
注意:
|
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トランスレータのオプションによってサポートされる次の設定は、サーバー側トランスレータでは固定です。
サーバーでは、オンライン・セマンティクス・チェックとオフライン解析の両方がデフォルトで有効であり、これはクライアントでのデフォルトの-parse=both
設定に相当します。この設定をオーバーライドして、オンライン・セマンティクス・チェックをonline
オプションで無効にすることはできますが、オフライン解析を無効にすることはできません。
サーバー側では、Oracle固有コード生成が使用されます。これは、クライアント側のデフォルトの-codegen=oracle
設定に相当します。この設定は固定です。
サーバー側での変換時に生成されたクラス・スキーマ・オブジェクトは、SQLJソース・コードをマッピング先とする行番号を自動的に参照します。クライアント側での変換時に-linemap
オプションを有効化すると、サーバー側と同様の自動参照が行われます。
このオプションには、サーバー側にロードするときのソース・コードの解釈に使用するエンコーディングを指定します。encoding
オプションは、ソースのロード時にコンパイルの有無にかかわらず、使用されます。また、loadjava
を使用してSQLJアプリケーションをサーバー側にロードする別の方法としては、loadjava
コマンドラインでエンコーディングを指定する方法もあります。loadjava
コマンドラインで設定された文字エンコーディングは、このencoding
オプションに優先します。
注意: このオプションまたはloadjava で文字エンコーディングが指定されていない場合は、loadjava を実行したクライアントのfile.encoding で指定された文字エンコーディングが使用されます。 |
online
オプションにtrue
(デフォルト値)を設定すると、オンライン・セマンティクス・チェックが有効になります。セマンティクス・チェックは、ソースがロードされたスキーマに対して行われます。クライアント側でのオンライン・チェックでは、基本スキーマの指定は不要です。online
オプションをfalse
に設定すると、オフラインでチェックが行われます。
いずれの場合も、デフォルトのチェッカはoracle.sqlj.checker.OracleChecker
です。このチェッカにより、使用するJDBCドライバのバージョンとOracleのバージョンに応じてチェッカが選択されます。
online
オプションは、ソースの変換およびコンパイル時に使用されます。loadjava
-resolve
オプションを有効にしてこれをロードすると、即座に実行されます。それ以外の場合は、ソースで定義されたクラスを最初に使用しようとしたときに実行されます(変換およびコンパイルは暗黙的に行われます)。
注意: サーバー側とクライアント側とでは、online オプションの使用方法が異なります。サーバー側でonline オプション使用した場合、デフォルトのチェッカでのオンライン・チェックを有効にするフラグとしてのみ機能します。一方、クライアント側では、使用するチェッカを-online オプションで指定できますが、別途-user オプションでオンライン・チェックを有効にする必要があります。 |
このオプションにtrue
を設定すると、.sqlj
または.java
ソース・ファイルがサーバーでコンパイルされるときに、サーバー側のJavaコンパイラがデバッグ情報を出力します。これは、クライアント上で標準のjavac
コンパイラを実行するときに、-g
オプションを使用するのに相当します。
loadjava
-resolve
オプションを使用した場合、ロード中にソースがコンパイルされます。.sqlj
ファイルの場合は、SQLJ変換の直後に実行されます。-resolve
オプションを使用しない場合は、ソースで定義されたクラスを最初に使用しようとしたときに暗黙的な変換およびコンパイルが実行されます。
サーバーで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.sqlj
がx.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開発者ガイド』を参照してください。
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マルチスレッドを使用するプログラムは、変更を加えなくても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文が同じ実行コンテキスト・インスタンスを同時に使用できるようになっています。
ここでは、再帰的な状況の例を考えて、実行コンテキスト・インスタンスのステータス情報がどのようになるかを説明します。すべての文で、デフォルトの接続コンテキスト・インスタンスとそのデフォルトの実行コンテキスト・インスタンスが使用されると想定します。ストアド・プロシージャproc1
が持つSQLJ文が、同じくSQLJ文を持つストアド・プロシージャproc2
をコールする場合、proc2
内の各文は、proc1
のプロシージャ・コールが使用しているときに同じ実行コンテキスト・インスタンスを使用します。
proc2
の各SQLJ文によって、その文のステータス情報が実行コンテキスト・インスタンスに書き込まれるため、必要な場合は、各文の完了後にその情報を取得することができます。proc2
をコールするproc1
の文からステータス情報が実行コンテキスト・インスタンスに書き込まれるのは、proc2
の実行が終了し、プログラム・フローがproc1
に戻り、proc2
をコールしたproc1
内の操作が完了した後です。
再帰的な状況でも実行コンテキストのステータス情報が正しく処理されるように、実行コンテキスト・メソッドは、SQL操作が完了した後にステータス情報を更新するように定義されています。
注意:
|
作成したコードが実際にサーバー側で実行可能かどうかを確認する場合、java.lang.System
クラスのstatic getProperty()
メソッドを使用してoracle.server.version
のJavaプロパティを取得する方法が便利です。このプロパティにバージョン番号が指定されている場合、コードはサーバーで実行されます。このバージョン番号がNULL
の場合、Oracleサーバーではコードが実行されません。次にその例を示します。
... if (System.getProperty("oracle.server.version") != null { // (running in server) } ...
注意: サーバー側でgetProperties() メソッドは使用しないでください。セキュリティ例外の原因となります。 |