4 プログラミング上の主な考慮事項
この章では、SQLJアプリケーションの開発および実行前に検討する必要がある重要な問題について説明し、要約とサンプル・アプリケーションも示します。次の内容について説明します。
4.1 JDBCドライバの選択
Java Database Connectivity(JDBC)ドライバの選択にあたっては、変換時と実行時にそれぞれ別のドライバを使用するかどうかを検討する必要があります。変換用と実行用の各ドライバ・クラスを選択または登録し、そのドライバを接続URLで指定してください。
注意:
Oracle固有コード生成を使用する場合、またはISO SQLJ標準コード生成とOracleカスタマイザを使用する場合は、Oracle JDBCドライバが必要です。Oracle固有の機能を実際には使用しない場合にも必要です。
この項の内容は次のとおりです。
4.1.1 Oracle JDBCドライバの概要
Oracle JDBCドライバを次に示します。
-
Oracle Call Interface(OCI)ドライバ: Oracleクライアント環境とともにクライアント側で使用します。
-
Thinドライバ: Pure Javaで記述されたドライバで、クライアント側で特にアプレットから使用します。Oracleクライアント環境は不要です。
-
サーバー側Thinドライバ: クライアント側Thinドライバと同様の機能を備えていますが、Oracle Databaseインスタンス内で実行するコード用のドライバでありリモート・サーバーにアクセスするためのものです。
-
サーバー側内部ドライバ: ターゲット・サーバー内(つまり、アクセスするOracle Databaseインスタンス内)で実行するコード用のドライバ。
Oracle Database 12c リリース1 (12.1)ではJDK 6およびJDK 7と互換性があるクライアント側ドライバが用意されています。
注意:
変換時と実行時とで、別々のドライバを選ぶ場合もあります。具体的には、変換時のセマンティクス・チェックにはOracle JDBC OCIドライバを使用し、実行時にはOracle JDBC Thinドライバを使用します。
JDBCの中核となる機能
Oracle JDBCドライバは、いずれも同様の機能性を備えています。各ドライバでサポートされている機能セット、構文、プログラミング・インタフェースおよびOracle拡張型は、すべて同じです。
Oracle JDBCドライバはすべて、oracle.jdbc.OracleDriver
クラスでサポートされています。
JDBC OCIドライバ
Oracle JDBC OCIドライバでは、OCIを直接Javaからコールしてデータベースにアクセスできるため、Oracle Databaseの様々なバージョンとの高度な互換性が確保されています。これらのドライバでは、インストール済Oracle Netアダプタ(プロセス間通信(IPC)、Named Pipes、TCP/IP、IPX/SPXなど)がサポートされています。
ネイティブ・メソッドを使用してCエントリ・ポイントをコールする際、このOCIドライバはOracleプラットフォームに依存するため、Oracle NetをはじめとするOracleクライアントのインストールが必要になります。このため、これはアプレットには適していません。
OCIドライバ用の接続文字列は次の形式になります(tns
は、オプションでTNSの別名またはTNS完全指定です)。
jdbc:oracle:oci:@<tns>
注意:
下位互換性のため、oci
のかわりにoci8
も使用できます。
JDBC Thinドライバ
Oracle JDBC Thinドライバは、プラットフォームに依存しないPure Javaの実装であり、Javaソケットを使用してOracleまたはOracle以外のクライアントから直接Oracle Databaseに接続できます。アプレットの実行と同時にこのドライバをブラウザにダウンロードすることも可能です。
このJDBC Thinドライバでは、TCP/IPプロトコルしかサポートされていないため、データベース・サーバーからのTCP/IPソケットをリスニングするTNSリスナーが必要です。このJDBC Thinドライバとアプレットとを併用する場合、Javaソケットをサポートしているクライアント・ブラウザを使用してください。
JDBC Thinドライバ用の接続文字列は、通常次の形式です。
jdbc:oracle:thin:@host:port/servicename
関連項目:
データベース・サービス名の詳細は『Oracle Database JDBC開発者ガイド』を参照してください
Oracle Database 12c リリース2 (12.2)では、SIDを使用した接続文字列は非推奨ですが、下位互換性の目的で引き続きサポートされています。
jdbc:oracle:thin:@host:port:sid
JDBCサーバー側Thinドライバ
Oracle JDBCサーバー側のThinドライバは、クライアント側のJDBC Thinドライバと同様の機能性を備えていますが、さらにデータベース内で動作し、リモート・サーバーにアクセスできます。このドライバは、あるOracle Databaseインスタンス内部(Javaストアド・プロシージャなど)から別のOracle Databaseインスタンスへのアクセスに利用できます。
サーバー側Thinドライバ用の接続文字列は、クライアント側Thinドライバ用と同じです。
注意:
サーバー側Thinドライバの使用時に、元のデータベースをそのままにしておくためには、ユーザー・アカウントにSocketPermission
を割り当てる必要があります。詳細は、『Oracle Database JDBC開発者ガイド』を参照してください。また、SocketPermission
および他のアクセス権の概要は、『Oracle Database Java開発者ガイド』を参照してください。
サーバー側JDBC内部ドライバ
Oracle JDBCサーバー側内部ドライバは、SQL操作を行うターゲットのOracle Databaseインスタンスで実行される、あらゆるJavaコードをサポートしています。サーバー側内部ドライバを使用すると、Oracle Java Virtual Machine(JVM)から直接SQLエンジンに通信できるようになります。このドライバは、Oracle Database 12c リリース2 (12.2)でストアド・プロシージャ、ストアド・ファンクションまたはトリガーとしてSQLJコードを実行するためのデフォルトのJDBCドライバです。
jdbc:oracle:kprb:
SQLJコードでデフォルトの接続コンテキストを使用する場合、SQLJでは、Oracle JVMで実行するコード用に自動的にこのドライバが使用されます。
4.1.2 変換用ドライバの選択
ドライバ・マネージャ・クラスを選択し、変換用のドライバを指定するには、コマンドラインまたはプロパティ・ファイルでSQLJオプションを設定します。
OracleDriver
(デフォルト)以外のドライバ・マネージャ・クラスを選択するには、SQLJの-driver
オプションを使用します。
SQLJの-url
オプションで接続URLを指定するときは、Oracle Database用のJDBC ThinドライバやJDBC OCIドライバなど、選択した特定のJDBCドライバも一緒に指定します。
関連項目:
通常は、ソース・コードでランタイム接続用に指定したドライバを使用します。
注意:
前述の-driver
オプションは、特定のドライバの選択には使用できません。このオプションを使用すると、ドライバ・マネージャにあるドライバ・クラスを登録します。そのドライバ・クラスは、複数のドライバ・プロトコル(すべてのOracle JDBCプロトコルで使用されるOracleDriver
など)に使用できます。
4.1.3 実行時に使用するドライバの選択および登録
実行時にデータベースに接続するには、接続インスタンス(sqlj.runtime.ref.DefaultContext
クラスまたは宣言済の接続コンテキスト・クラスのインスタンス)のいずれかに対して指定したURLを認識するドライバを1つ以上登録する必要があります。
Oracle JDBCドライバを使用している場合に、Oracle.connect()
メソッドでデフォルトの接続を作成すると、SQLJはこれを自動的に処理します。Oracle.connect()
メソッドによって、oracle.jdbc.OracleDriver
クラスが登録されます。
Oracle JDBCドライバを使用し、Oracle.connect()
を使用しない場合は、次のようにOracleDriver
クラスを手動で登録する必要があります。
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Oracle JDBCドライバを使用しない場合は、次のように適切なドライバ・クラスを登録する必要があります。
DriverManager.registerDriver(new mydriver.jdbc.driver.MyDriver());
どの場合でも、接続URL、ユーザー名およびパスワードの設定が必要です。
注意:
JDBC接続を確立する際にJDBCドライバ・マネージャのかわりに、データ・ソースを使用することができます。「WITH句宣言」で説明するように、with
句にデータ・ソースを指定できます。データ・ソースの概要は、『Oracle Database JDBC開発者ガイド』を参照してください。
4.2 接続の際の考慮事項
SQLJアプリケーションで使用するデータベース接続の選択にあたっては、次の点を考慮してください。
-
必要なデータベース接続が単一であるか複数であるか。
-
複数の接続(また、必要に応じて複数のスキーマ)を使用する場合、各接続で同じ名前のSQLエンティティ、つまり、表の名前、列の名前とデータ型、ストアド・プロシージャの名前とシグネチャなどは、各接続のたびに同じ名前のものを使用するか。
-
変換時と実行時にそれぞれ別の接続を使用するか、同じ接続を使用するか。
データベース接続用の接続コンテキストのインスタンス(DefaultContext
または宣言した接続コンテキスト・クラスのインスタンス)は、SQLJ実行文で指定します。接続コンテキスト仕様を指定せずに、デフォルトの接続(デフォルトとしてあらかじめ設定したDefaultContext
のインスタンス)を使用することも可能です。
注意:
操作の際に数種類のSQLエンティティを使用する場合は、通常、新たに接続コンテキスト・クラスを宣言し、使用します。
この項の内容は次のとおりです。
4.2.1 DefaultContextを使用した単一接続または複数接続
ここでは、DefaultContext
クラスの接続インスタンスのみを使用する場合について説明します。
単一接続や、名前とデータ型が同じSQLエンティティを使用する複数接続では、代表的な方法です。
単一接続
単一接続の場合は、DefaultContext
クラスのインスタンスを1つ使用します。DefaultContext
オブジェクトの作成時に、データベースURL、ユーザー名およびパスワードを指定します。
この作業は、oracle.sqlj.runtime.Oracle
クラスのconnect()
メソッドで行えます。このメソッドをコールすると、デフォルトの接続コンテキスト・インスタンスが自動的に初期化されます。このメソッドには複数のシグネチャがあり、たとえば、ユーザー名、パスワードおよびURLを直接指定できるものや、プロパティ・ファイルに指定するものがあります。次に、プロパティ・ファイルconnect.properties
を使用した例を示します。
Oracle.connect(MyClass.class, "connect.properties");
注意:
connect.properties
ファイルは、指定したクラスに基づいて検索されます。たとえばMyClass
がmy-package
にある場合、connect.properties
は同じパッケージの場所であるmy-package
で検索されます。
connect.properties
を使用する場合は、必要な編集とアプリケーションでのパッケージ化を行ってください。この例では、oracle.sqlj.runtime.Oracle
クラスのインポートも必要です。
次のようにすると、ユーザー名、パスワードおよびURLを直接指定できます。
Oracle.connect("jdbc:oracle:thin:@localhost:5221/myservice", "HR", "hr");
この例では、JDBC Thinドライバを使用してHR
ユーザー(パスワードhr
)をコンピュータlocalhost
上のデータベースに、ポート5221
経由で接続します。myservice
は、接続用のデータベース・サービスの名前です。
どちらの場合も、DefaultContext
クラスの特別な静的インスタンスが生成され、デフォルトの接続としてインストールされます。DefaultContext
のインスタンスを直接操作する必要はありません。
ここまでの手順を終えた後、アプリケーションのSQLJ実行文に対していっさい接続を指定しないことも可能です。ただし、その場合は常にデフォルトの接続が使用されます。
JDBC Thinドライバを使用する場合は、前の例で示したように、ホスト名、ポート番号およびサービス名(またはSID、ただしOracle Database 12c リリース2 (12.2)では非推奨)をURLに含める必要があります。また、データベースには、指定したポートで実行されるリスナーが必要です。JDBC OCIドライバを使用する場合、クライアントのデフォルト・アカウントを使用するときはサービス名(またはSID)は不要です。このドキュメントの例はこれに該当します。また、名前-値ペアを使用することもできます。
関連項目:
詳細は、『Oracle Database JDBC開発者ガイド』を参照してください
次のURLでは、クライアントのデフォルト・アカウントに接続できます。
jdbc:oracle:oci:@
注意:
-
デフォルトの接続がすでに設定されていれば、
Oracle.connect()
を指定した場合でもデフォルトの接続が再設定されることはありません。この場合は、NULL
が戻されます。この機能により、クライアントとサーバーで同じコードを使用できます。デフォルトの接続を指定変更するには、DefaultContext
のstaticsetDefaultContext()
メソッドを使用します。 -
Oracle.connect()
メソッドの自動コミット・フラグのデフォルト値はfalse
です。ただし、このメソッドのシグネチャは明示的に設定できます。Oracle JDBC実装の自動コミット・フラグのデフォルト値はtrue
です。 -
Oracle.connect()
をコールする際に、必要に応じて、MyClass.class
のかわりにgetClass()
を指定できますが、この指定はgetClass()
をstaticメソッドからコールしない場合にのみ有効です。getClass()
メソッドは、一部のSQLJデモ・アプリケーションで使用されています。 -
次のように、static
DefaultContext
インスタンスに接続できます。これは、デフォルトの接続に対応しています。DefaultContext.getDefaultContext();
複数接続
複数接続の場合は、DefaultContext
クラスのインスタンスをさらに作成して使用します。デフォルト接続もそのまま使用できます。
DefaultContext
のインスタンス化するには、次の例のようにOracle.getConnection()
メソッドを使用します。
最初に、デフォルト接続を大半の文で使用し、残りの文では別の接続を使用するとします。DefaultContext
のインスタンスを新たに1つ作成する必要があります。
DefaultContext ctx = Oracle.getConnection ( "jdbc:oracle:thin:@localhost2:5221/myservice2", "bill", "lion");
注意:
同一スキーマに対して複数の操作を行う場合は、ctx
でHR
/hr
スキーマを使用することも可能です。
デフォルトの接続を使用する場合は、接続コンテキストを指定する必要はありません。
#sql { SQL operation };
これは実際には、次の形式を省略しています。
#sql [DefaultContext.getDefaultContext()] { SQL operation };
追加した接続を使用する場合は、接続としてctx
を指定します。
#sql [ctx] { SQL operation };
次に、複数の接続を使用する状況を想定し、各接続を名前付きDefaultContext
インスタンスにします。これによって、接続を交互に切り替えることができます。
次の文は、同一スキーマに対して複数の接続を確立します(複数のOracle Databaseセッションやトランザクションを使用する場合など)。接続ごとにDefaultContext
クラスをインスタンス化します。
DefaultContext ctx1 = Oracle.getConnection ("jdbc:oracle:thin:@localhost1:5221/myservice1", "HR", "hr"); DefaultContext ctx2 = Oracle.getConnection ("jdbc:oracle:thin:@localhost1:5221/myservice1", "HR", "hr");
接続コンテキストのインスタンスが2つ作成されます。どちらも、Oracle JDBC Thinドライバを介して、コンピュータlocalhost1
上でサービスmyservice1
を使用してHR/hr
に接続します。
次に、スキーマごとにそれぞれ別の接続を使用する場合を想定します。この場合も、接続ごとにDefaultContext
クラスをインスタンス化します。
DefaultContext ctx1 = Oracle.getConnection ("jdbc:oracle:thin:@localhost1:5221/myservice1", "HR", "hr"); DefaultContext ctx2 = Oracle.getConnection ("jdbc:oracle:thin:@localhost2:5221/myservice2", "bill", "lion");
接続コンテキストのインスタンスが2つ作成されます。この2つのインスタンスは、Oracle JDBC Thinドライバを使用し、それぞれ別のスキーマを使用します。ctx1
オブジェクトは、コンピュータlocalhost1
上のサービスmyservice1
を使用してHR/hr
に接続し、ctx2
オブジェクトは、コンピュータlocalhost2
上のサービスmyservice2
を使用してbill/lion
に接続します。
アプリケーションのSQLJ実行文でこれらの接続を交互に切り替える方法には、次の2通りがあります。
-
接続の切替え頻度が高い場合に、アプリケーションの各文に対して、次のように接続を指定する方法。
#sql [ctx1] { SQL operation }; ... #sql [ctx2] { SQL operation };
注意:
接続コンテキストのインスタンスの名前は、必ず大カッコで囲みます。大カッコも構文の構成要素です。
-
コード・フロー内の行で片方の接続を複数回連続して使用する場合、デフォルト接続をリセットするために、
DefaultContext
クラスのstaticsetDefaultContext()
メソッドを定期的に使用する方法。このメソッドによって、デフォルトの接続コンテキスト・インスタンスが初期化されます。この方法では、SQLJ文で接続を指定する必要がありません。DefaultContext.setDefaultContext(ctx1); #sql { SQL operation }; // These three statements all use ctx1 #sql { SQL operation }; #sql { SQL operation }; ... DefaultContext.setDefaultContext(ctx2); #sql { SQL operation }; // These three statements all use ctx2 #sql { SQL operation }; #sql { SQL operation };
注意:
前述の文では接続コンテキストを指定していないため、変換時にデフォルトの接続コンテキストかどうかが文ごとにチェックされます。
4.2.2 接続の終了
接続が完了した後、接続コンテキスト・インスタンスをクローズしてください。try
ブロックのfinally
句(アプリケーションが例外時に終了した場合)でクローズを指定することをお薦めします。
DefaultContext
クラス、および宣言したその他のあらゆる接続コンテキスト・クラスには、close()
メソッドが用意されています。このclose()メソッドをコールすると、SQLJ接続コンテキスト・インスタンスが終了し、デフォルトでは、基になるJDBC接続インスタンスおよび物理的な接続も終了します。
また、oracle.sqlj.runtime.Oracle
クラスに用意されているstatic close()
メソッドを使用すると、デフォルトの接続のみが終了します。次の例では、あらゆる接続コンテキスト・クラスのインスタンスをctx
として示した場合を想定しています。
... finally { ctx.close(); } ...
SQL例外が発生して、finally
句がtry
ブロック内にない場合は、次のようになります。
... finally { try { ctx.close(); } catch(SQLException ex) {...} } ...
デフォルトの接続を終了する方法としては、Oracle
クラスに用意されているclose()
メソッドを使用する方法もあります。
... finally { Oracle.close(); } ...
接続を終了する前に、必ず保留中の変更をコミットまたはロールバックしてください。接続を閉じる際に暗黙的なCOMMIT
操作が行われるかどうかは、JDBC規格では指定されておらず、またベンダーによっても異なります。Oracleの場合、接続を終了する際に暗黙的なCOMMIT
が行われるようになっており、接続が終了されずにガベージ・コレクションが行われた場合は暗黙的なROLLBACK
が行われるようになっていますが、これらのメカニズムに頼るのはお薦めできません。
注意:
基になる接続(共有接続の場合)を終了せずに、接続コンテキスト・インスタンスを終了することも可能です。
4.2.3 宣言済の接続コンテキスト・クラスを使用した複数接続
数種類のSQLエンティティを使用した接続の場合は、接続コンテキストの宣言によって、接続コンテキスト・クラスをさらに定義すると利便性が高まります。使用するSQLエンティティごとに個別の接続コンテキスト・クラスを作成すると、SQLJではコードのセマンティクス・チェックがより厳密に行われます。
関連項目:
4.2.4 Oracleクラスについて
Oracle SQLJ実装のoracle.sqlj.runtime.Oracle
クラスでは、DefaultContext
クラスのインスタンスを簡単に作成して使用できます。
static connect()
メソッドは、デフォルトの接続コンテキスト・インスタンスを初期化します(DefaultContext
オブジェクトのインスタンスを作成し、デフォルトの接続としてインストールします)。connect()
から戻されたDefaultContext
のインスタンスの代入や使用は、任意に行ってください。デフォルトの接続がすでに確立されていると、connect()
からNULL
が戻されます。
static getConnection()
メソッドでは、単にDefaultContext
オブジェクトのインスタンスが生成され、そのインスタンスが戻されます。必要に応じて、戻されたインスタンスを使用できます。
oracle.jdbc.OracleDriver
クラスをCLASSPATH
に指定すると、どちらのメソッドを使用してもOracle JDBCドライバ・マネージャが自動的に登録されるようになります。static close()
メソッドは、デフォルトの接続を終了するメソッドです。
Oracle.connect()メソッドおよびOracle.getConnection()メソッドのシグネチャ
いずれのメソッドにも、入力として次のパラメータをとるシグネチャがあります。
-
URL (
String
)、ユーザー名(String
)、パスワード(String
) -
URL (
String
)、ユーザー名(String
)、パスワード(String
)、自動コミット・フラグ(boolean
) -
URL(
String
)、java.util.Properties
オブジェクト(接続のプロパティが格納されているオブジェクト) -
URL(
String
)、java.util.Properties
オブジェクト、自動コミット・フラグ(boolean
) -
ユーザー名やパスワードなど、接続を詳細に指定するURL(
String
)次に示すURL文字列の形式の例では、ユーザー名(
HR
)およびパスワード(hr
)が指定されており、Oracle JDBCドライバとしてはJDBC Thinドライバが使用されています。"jdbc:oracle:thin:HR/hr@localhost:5221/myservice"
-
URL(
String
)、自動コミット・フラグ(boolean
) -
クラスの
java.lang.Class
オブジェクト(そのクラスに基づいてプロパティ・ファイルがロードされる)、プロパティ・ファイル名(String
) -
java.lang.Class
オブジェクト、プロパティ・ファイル名(String
)、自動コミット・フラグ(boolean
) -
java.lang.Class
オブジェクト、プロパティ・ファイル名(String
)、ユーザー名(String
)、パスワード(String
) -
java.lang.Class
オブジェクト、プロパティ・ファイル名(String
)、ユーザー名(String
)、パスワード(String
)、自動コミット・フラグ(boolean
) -
JDBC接続オブジェクト(
Connection
) -
SQLJ接続コンテキスト・オブジェクト
最後の2つのシグネチャは既存のデータベース接続を継承します。接続を継承すると、その接続に対する自動コミットの設定も継承されます。
自動コミット・フラグは、SQL操作を自動的にコミットするかしないかを指定するフラグです。Oracle.connect()
メソッドおよびOracle.getConnection()
メソッドの場合にのみ、デフォルトはfalse
になっています。デフォルト値を使用すると、入力として自動コミットをとらないシグネチャを使用できます。ただし、コンストラクタを使用して、DefaultContext
などの接続コンテキスト・クラスのインスタンスを作成する場合は、自動コミットの設定を指定する必要があります。Oracle JDBC実装の自動コミット・フラグは、デフォルトとしてtrue
をとります。
Oracle.close()メソッドのオプションのパラメータ
Oracle.close()
を使用してデフォルト接続を閉じる際に、基になる物理的なデータベース接続を終了するかどうかを指定できます。デフォルトでは接続の終了が指定されます。この指定は、物理的な接続を複数の接続オブジェクト(SQLJ接続コンテキスト・インスタンスまたはJDBC接続インスタンス)で共有している場合に関係します。
基になる物理的な接続を、オープンした状態に保つには、次のようにします。
Oracle.close(ConnectionContext.KEEP_CONNECTION);
基になる物理的な接続を終了するには、次のようにします(デフォルトの動作)。
Oracle.close(ConnectionContext.CLOSE_CONNECTION);
KEEP_CONNECTION
およびCLOSE_CONNECTION
は、ConnectionContext
インタフェースのstatic定数です。
関連項目:
4.2.5 DefaultContextクラスについて
sqlj.runtime.ref.DefaultContext
クラスは、接続コンテキスト・クラスの完全なデフォルト実装を提供します。接続コンテキストを宣言して作成したクラスと同じように、DefaultContext
クラスもsqlj.runtime.ConnectionContext
インタフェースを実装します。DefaultContext
クラスのクラス定義は、次のように宣言したときにSQLJトランスレータで生成される定義と同じです。
#sql public context DefaultContext;
DefaultContextメソッド
DefaultContext
クラスの主なメソッドを次に示します。
-
getConnection()
基になるJDBC接続オブジェクトを取得します。これは、動的SQL操作を使用する1つの方法として、アプリケーションにJDBCコードを使用する場合に役立ちます。基になるJDBC接続オブジェクトの
setAutoCommit()
メソッドを使用すると、接続の自動コミット・フラグを設定できます。 -
setDefaultContext()
アプリケーションで使用するデフォルトの接続を設定します。これは、入力として
DefaultContext
インスタンスをとるstatic
メソッドです。SQLJ実行文で接続コンテキストのインスタンスを指定しないと、このメソッドまたはOracle.connect()
メソッドを使用して定義したデフォルトの接続が使用されます。 -
getDefaultContext()
アプリケーションのデフォルト接続として現在定義されている
DefaultContext
インスタンスを戻します。これは、static
メソッドです。 -
close()
接続コンテキスト・インスタンスをクローズします。
getConnection()
メソッドおよびclose()
メソッドは、sqlj.runtime.ConnectionContext
インタフェースで指定します。
注意:
クライアント側では、setDefaultContext()
をあらかじめコールしないと、getDefaultContext()
からの戻り値がNULL
になります。ただし、データ・ソース・オブジェクトがJNDIのjdbc/defaultDataSource
下にバインドされている場合は、クライアントでデフォルトの接続としてこのデータ・ソース・オブジェクトが使用されます。
サーバーでは、getDefaultContext()
によってデフォルトの接続(サーバー自体への接続)が戻されます。
DefaultContextコンストラクタ
通常は、Oracle.connect()
またはOracle.getConnection()
メソッドを使用してDefaultContext
をインスタンス化します。ただし、DefaultContext
の場合、5つのコンストラクタのうちのいずれかを使用すると、インスタンスを直接作成できます。これらのコンストラクタには、次の異なる入力パラメータ・セットがあります。
-
URL (
String
)、ユーザー名(String
)、パスワード(String
)、自動コミット(boolean
) -
URL(
String
)、java.util.Properties
オブジェクト、自動コミット(boolean
) -
URL(ユーザー名やパスワードなど、接続の詳細を指定する
String
)、自動コミットの設定(boolean
)次に示すURLの形式の例では、ユーザー名およびパスワードが指定されており、Oracle JDBCドライバとしてはJDBC Thinドライバが使用されています。
"jdbc:oracle:thin:HR/hr@localhost:5221/myservice"
-
JDBC接続オブジェクト(
Connection
) -
SQLJ接続コンテキスト・オブジェクト
最後の2つのシグネチャは既存のデータベース接続を継承します。接続を継承すると、その接続に対する自動コミットの設定も継承されます。
DefaultContext
インスタンスを作成する例を、次に示します。
DefaultContext defctx = new DefaultContext ("jdbc:oracle:thin:@localhost:5221/myservice", "HR", "hr", false);
接続コンテキスト・コンストラクタに関する注意:
注意:
接続コンテキスト・コンストラクタを使用する際は、次の点に注意する必要があります。
-
接続コンテキスト・クラスは、
Oracle.connect()
メソッドとは異なり、自動コミットの設定が必要です。 -
前述のコンストラクタのうち、最初の3つを使用するには、あらかじめJDBCドライバを登録する必要があります。ドライバを自動的に登録するには、Oracle JDBCドライバを使用し、
Oracle.connect()
をコールします。「実行時に使用するドライバの選択および登録」を参照してください。 -
通常宣言する接続コンテキスト・クラスのコンストラクタ・シグネチャは、
DefaultContext
クラスと同じです。ただし、接続コンテキスト・クラスをデータ・ソースに対応付けるように宣言する場合、別のコンストラクタが用意されています。詳細は、「標準データ・ソースのサポート」を参照してください。 -
JDBC接続オブジェクトを引数とするコンストラクタを使用する場合は、接続コンテキスト・インスタンスをNULL JDBCで初期化しないでください。
-
自動コミットの設定では、SQL操作が自動的にコミットされるかどうかが定義されます。詳細は、「基本的なトランザクション制御」を参照してください。
DefaultContext close()メソッドのオプションのパラメータ
接続コンテキスト・インスタンスを終了するとき、基になる物理的な接続を終了するかどうかを指定できます。デフォルトでは接続の終了が指定されます。この指定は、複数の接続オブジェクト(SQLJ接続コンテキスト・インスタンスまたはJDBC接続インスタンス)で物理的な接続を共有している場合に有効です。DefaultContext
インスタンスのdefctx
を前提とした例を、いくつか次に示します。
基になる物理的な接続をオープンした状態に保つには、次の構文を使用します。
defctx.close(ConnectionContext.KEEP_CONNECTION);
基になる物理的な接続を終了する(デフォルトの動作)には、次の構文を使用します。
defctx.close(ConnectionContext.CLOSE_CONNECTION);
KEEP_CONNECTION
およびCLOSE_CONNECTION
は、ConnectionContext
インタフェースのstatic定数です。
関連項目:
これらのパラメータの使用方法および共有接続の詳細は、「共有接続の終了」を参照してください
4.2.6 変換時の接続
変換時にオンラインのセマンティクス・チェックを使用する場合、SQLJで使用するデータベース接続を指定する必要があります。これらは、基本スキーマといいます。
関連項目:
変換時と実行時で別々の接続を使用できます。実際、別々の接続を使用する必要がある場合、またそれが推奨される場合が多くあります。現在開発を行っている環境と将来アプリケーションを実行する環境とが異なる場合は、別々の接続を使用する必要が生じる場合があります。変換時にランタイム接続を使用できる場合でも、オンライン・チェックの精度を高めるためにはリソースを絞り込んでアカウントを作成する方が望ましいといえます。実際にこの精度を高めるには、ランタイム接続時に使用可能なSQLエンティティうち、アプリケーションで使用するSQLエンティティのサブセットを少量にします。アプリケーションで実際に使用するSQLエンティティのみに絞り込んだ基本スキーマを作成すると、オンライン・チェックの精度と信頼度が高まります。
変換時の接続を指定するには、コマンドラインまたはプロパティ・ファイルでSQLJトランスレータの接続オプションを使用します。
関連項目:
4.2.7 カスタマイズ時の接続
一般に、Oracleのカスタマイズではデータベース接続は不要です。ただし、Oracle SQLJ実装ではカスタマイザ接続がサポートされています。これは、2つの環境で利用できます。
-
使用するOracleカスタマイザの
optcols
オプションを使用可能にすると、接続が必須になります。このオプションを使用すると、イテレータ列型およびサイズは、パフォーマンスが最適化されるように定義されます。 -
SQLCheckerCustomizer
と呼ばれる、プロファイルに対してセマンティクス・チェックを実行する特別なカスタマイザを使用した場合、オンライン・チェッカ(デフォルトでは使用)を使用するためには接続が必要になります。
Oracle固有コード生成の場合は、SQLJトランスレータに、同じ機能を持つ-optcols
オプションがあります。SQLCheckerCustomizer
は、Oracleカスタマイザ・ハーネスのverify
オプションを指定すると起動されるようになります。どのカスタマイザを使用する場合にも、必要に応じて、カスタマイザ・ハーネスのuser
、password
、url
およびdriver
オプションを使用して、接続パラメータを指定します。
4.3 NULLの処理
Javaの基本型(int
、double
、float
など)は、null値をとりません。結果式およびホスト式の型を選択するときは、このことに注意してください。
この項の内容は次のとおりです。
4.3.1 NULL処理用のラッパー・クラス
JDBCではNULL
を0
または特定のデータ型に対してはfalse
として取り出されますが、SQLJではSQLのNULL
は、常にJavaのnull
として取り出されます。そのため、SQLでNULL
を受け取る可能性がある場合に、SQLJで出力変数にJavaの基本型を使用しないでください(Javaの基本型は、null
値をとらないためです)。
このことは、結果式、出力ホスト式、入出力ホスト式およびイテレータ列の型について当てはまるので、注意が必要です。Javaの基本型を受取り用にしてSQLのNULL
を取り出そうとすると、sqlj.runtime.SQLNullException
が発生し、代入が行われなくなります。
Javaの基本型にNULL
値が代入されるのを避けるには、基本型のかわりに次のラッパー・クラスを使用します。
-
java.lang.Boolean
-
java.lang.Byte
-
java.lang.Short
-
java.lang.Integer
-
java.lang.Long
-
java.lang.Double
-
java.lang.Float
基本型の値に再変換する必要が生じた場合は、各ラッパー・クラスにxxx
Value()
メソッドがあります。たとえば、intValue()
を使用すると、int
値がInteger
オブジェクトから戻され、floatValue()
を使用すると、float
値がFloat
オブジェクトから戻されます。この例では、intobj
をInteger
オブジェクトとします。
int j = intobj.intValue();
注意:
-
SQLNullException
は、標準java.sql.SQLException
クラスのサブクラスです。 -
Javaオブジェクトは
NULL
値を持つことができます。SQLJでは、他のホスト言語(C、C++、COBOLなど)と異なり、インジケータ変数は不要です。
4.3.2 NULL処理の例
次に、java.lang
ラッパー・クラスを使用してNULL
を処理する例を示します。
NULL入力ホスト変数の例
次の例では、Float
オブジェクトを使用して、NULL
値をデータベースに渡します。
int empno = 7499; Float commission = null; #sql { UPDATE employees SET commission_pct = :commission WHERE employee_id = :empno };
この場合は、Javaの基本型float
を使用できません。
NULLイテレータ行の例
次の例では、NULL
データに対応できるように、イテレータにDouble
列型を使用します。
employee
表の従業員のうち、給与が$50,000以上の従業員の名前(FIRST_NAME
)と歩合(COMMISSION_PCT
)をイテレータに取り出します。次に各行をテストして、COMMISSION_PCT
フィールドが実際にNULLになっているかどうかを調べます。NULLの場合は、NULLの処理が行われます。
#sql iterator EmployeeIter (String first_name, Double commission); EmployeeIter ei; #sql ei = { SELECT first_name, commission_pct FROM employees WHERE salary >= 50000 }; while (ei.next()) { if (ei.commission_pct() == null) System.out.println(ei.first_name() + " is not on commission."); } ei.close(); ...
注意:
WHERE
句のNULL
値との比較を実行するには、次のSQL構文を使用します。
...WHERE :x IS NULL
4.4 例外処理の基本
ここでは、SQLJアプリケーションにおける例外処理の基本として、エラー・チェック要件などについて説明します。この項の内容は次のとおりです。
4.4.1 SQLJおよびJDBCの例外処理要件
SQLJ実行文は、sqlj.runtime
からのJDBCコールになり、JDBCではSQL例外が捕捉またはスローされる必要があるため、SQLJでも、SQLJ実行文を含むブロックで、SQL例外が捕捉またはスローされる必要があります。適切な例外処理が含まれていないと、ソース・コードのコンパイル中にエラーが生成されます。
SQL例外の処理には、SQLException
クラスが必要です。これは標準JDBCのjava.sql.*
パッケージに含まれています。
例外処理の例
SQLJアプリケーションに必要な基本的な例外処理の例です。このコードでは、try/catch
ブロックを含むmain
メソッド、および例外発生時にSQLException
をスローする別のメソッドを宣言します。このコードを次に示します。
/* Import SQLExceptions class. The SQLException comes from JDBC. Executable #sql clauses result in calls to JDBC, so methods containing executable #sql clauses must either catch or throw SQLException. */ import java.sql.* ; import oracle.sqlj.runtime.Oracle; // iterator for the select #sql iterator MyIter (String ITEM_NAME); public class TestInstallSQLJ { //Main method public static void main (String args[]) { try { // Set the default connection to the URL, user, and password // specified in your connect.properties file Oracle.connect(TestInstallSQLJ.class, "connect.properties"); TestInstallSQLJ ti = new TestInstallSQLJ(); // This method throws SQLException. Therefore, it ic called within a try block ti.runExample(); } catch (SQLException e) { System.err.println("Error running the example: " + e); } } //End of method main //Method that runs the example void runExample() throws SQLException { //Issue SQL command to clear the SALES table #sql { DELETE FROM SALES }; #sql { INSERT INTO SALES(ITEM_NAME) VALUES ('Hello, SQLJ!')}; MyIter iter; #sql iter = { SELECT ITEM_NAME FROM SALES }; while (iter.next()) { System.out.println(iter.ITEM_NAME()); } } }
4.4.2 例外の処理
ここでは、SQLJアプリケーションにおける例外の処理および解析方法について説明します。実行時の例外の発生元は次のいずれかです。
-
SQLJランタイム
-
JDBCドライバ
-
RDBMS
エラー・テキストの出力
前項の例では、SQL例外の捕捉方法およびエラー・メッセージの出力方法を示しました。このコードの一部を次に示します。
... try { ... } catch (SQLException e) { System.err.println("Error running the example: " + e); } ...
この結果、SQLException
オブジェクトからのエラー・テキストが出力されます。
エラー情報を取り出すには、SQLException
クラスのgetMessage()
、getErrorCode()
およびgetSQLState()
メソッドを使用します。
この例に示したようにエラー・テキストを出力すると、エラー・メッセージの他にSQLException
などのテキストも出力されます。
SQLの状態およびエラー・コードの取出し
java.sql.SQLException
クラスとサブクラスには、メソッドgetMessage()
、getErrorCode()
およびgetSQLState()
があります。次のメソッドを使用すると、例外またはエラーの発生元およびこれらの実装方法に応じて、次のような補足情報が得られます。
-
String getMessage()
SQLJランタイムまたはJDBCドライバで発生したエラーに対してこのメソッドを使用すると、接頭辞なしのエラー・メッセージが戻されます。RDBMSで発生したエラーに対してこのメソッドを使用すると、接頭辞として
ORA
番号の付いたエラー・メッセージが戻されます。 -
int getErrorCode()
SQLJランタイムで発生したエラーに対しては、このメソッドを使用しても役立つ情報は戻されません。JDBCドライバまたはRDBMSで発生したエラーに対してこのメソッドを使用すると、
ORA
番号が5桁の整数として戻されます。 -
String getSQLState()
SQLJランタイムで発生したエラーに対してこのメソッドを使用すると、SQLの状態を示す5桁のコードと文字列が戻されます。JDBCドライバで発生したエラーに対しては、このメソッドを使用しても役立つ情報は戻されません。RDBMSで発生したエラーに対してこのメソッドを使用すると、SQLの状態を示す5桁のコードが戻されます。アプリケーションには、
NULL
の戻り値を扱えるように適切なコードを含める必要があります。
次に、エラー・メッセージを出力し、さらにSQLの状態をチェックする例を示します。
... try { ... } catch (SQLException e) { System.err.println("Error running the example: " + e); String sqlState = e.getSQLState(); System.err.println("SQL state = " + sqlState); } ...
4.4.3 SQLExceptionサブクラスの使用方法
さらに細かいエラー・チェックを実行するには、java.sql.SQLException
クラスのサブクラスを使用します。
SQLJでは、java.sql.SQLException
のサブクラスであるsqlj.runtime.NullException
クラスが提供されます。この例外は、Javaの基本型変数にNULL
が戻される場合に使用できます。
バッチ処理が有効な環境では、標準java.sql.BatchUpdateException
サブクラスを使用できます。詳細は、「バッチ実行中のエラー状態」を参照してください。
SQLException
サブクラスを使用する際は、サブクラスの例外を捕捉してから、SQLException
を捕捉してください。次に例を示します。
... try { ... } catch (SQLNullException ne) { System.err.println("Null value encountered: " + ne); } catch (SQLException e) { System.err.println("Error running the example: " + e); } ...
このようにするのは、サブクラスの例外もSQLException
として捕捉できるからです。SQLException
を先に捕捉すると、サブクラスの例外に対して特別な処理が行われるコード部分まで進みません。
4.5 基本的なトランザクション制御
ここでは、データ更新を管理する方法について説明します。内容は次のとおりです。
関連項目:
4.5.1 トランザクションの概要
トランザクションは、Oracleで1つの単位として順次処理されるSQL操作です。次の処理を行った後のSQL実行文でトランザクションが開始されます。
-
データベースへの接続
-
COMMIT
(データの更新を自動的にまたは手動でデータベースにコミットします) -
ROLLBACK
(変更内容を取り消します)
トランザクションは、COMMIT
操作またはROLLBACK
操作で終了します。
注意:
Oracle Database 12c リリース2 (12.2)では、CREATE
、ALTER
などのすべてのデータ定義言語(DDL)文に暗黙的なCOMMIT
が含まれます。これによって、DDL文のみでなく、コミットまたはロールバックされていない、実行済のすべてのデータ操作言語(DML)文(INSERT
、DELETE
、UPDATE
など)もコミットされます。
4.5.2 自動コミットと手動コミットとの違い
SQLJまたはJDBCを使用すると、自動でも手動でも、データの更新をコミットできます。どちらの場合も、新規のトランザクションはCOMMIT
操作で開始されます。変更内容の自動コミットを指定するには、自動コミット・フラグを使用可能にします。これを行うには、SQLJ接続を定義するときに自動コミット・フラグを使用可能にするか、既存の接続の基になるJDBC接続オブジェクトのsetAutoCommit()
メソッドを使用します。手動で制御するには、自動コミット・フラグを使用禁止にし、SQLJのCOMMIT
文およびROLLBACK
文を使用します。
自動コミットを使用可能にすると、手間が省けますが、細かい制御ができません。たとえば、変更内容のロールバックができません。また、自動コミット・モードでは、SQLJやJDBCの一部の機能を使用できません。そのため、バッチ更新やSELECT FOR UPDATE
構文を使用する場合などは、自動コミット・フラグを使用禁止にする必要があります。
4.5.3 接続を定義する際の自動コミットの指定
Oracle.connect()
またはOracle.getConnection()
メソッドでDefaultContext
のインスタンスを作成し、接続を定義すると、自動コミット・フラグがデフォルトでfalse
に設定されます。ただし、これらのメソッドのシグネチャでは、このフラグを明示的に設定できます。自動コミット・フラグは、必ず最後のパラメータで指定します。
次に、DefaultContext
をインスタンス化し、自動コミット・モードのデフォルト値false
を使用する例を示します。
Oracle.getConnection ("jdbc:oracle:thin:@localhost:5221/myservice", "HR", "hr");
true
に設定するには、次のように指定します。
Oracle.getConnection ("jdbc:oracle:thin:@localhost:5221/myservice", "HR", "hr", true);
関連項目:
コンストラクタで接続コンテキストのインスタンスを作成する場合は、DefaultContext
クラスの場合でも、宣言済の接続コンテキスト・クラスの場合でも、自動コミットの設定を指定する必要があります。この設定のフラグも、次のように最後のパラメータで指定します。
DefaultContext ctx = new DefaultContext ("jdbc:oracle:thin:@localhost:5221/myservice", "HR", "hr", false);
関連項目:
JDBCのConnection
インスタンスを直接作成する理由がある場合、自動コミット・フラグの設定は、プログラムがクライアント側で実行されるときはデフォルトでtrue
になり、サーバー側で実行されるときはデフォルトでfalse
になります。JDBCのConnection
インスタンスを直接作成するときに自動コミットの設定値は指定できませんが、その設定をsetAutoCommit()
メソッドで変更することはできます。
注意:
自動コミット機能は、サーバー側のJDBC内部ドライバではサポートされていません。
4.5.4 既存の接続の自動コミットに対する変更
既存の接続の場合は、自動コミット・フラグの設定変更は通常不要ですが、必要な場合は変更できます。変更するには、基になるJDBC接続オブジェクトのsetAutoCommit()
メソッドを使用します。
基になるJDBC接続オブジェクトを取得するには、SQLJの接続コンテキスト・インスタンスのgetConnection()
メソッドを使用します。つまり、DefaultContext
クラスのインスタンスのメソッドを使用するか、または宣言済の接続コンテキスト・クラスのインスタンスのメソッドを使用します。
この2つの操作を一度に行うには、次のように指定します。
ctx.getConnection().setAutoCommit(false);
または
ctx.getConnection().setAutoCommit(true);
この例では、ctx
をSQLJの接続コンテキストのインスタンスとしています。
注意:
トランザクションの処理中は、自動コミットの設定を変更しないでください。
4.5.5 手動COMMITまたはROLLBACKの使用方法
自動コミット・フラグを使用禁止にした場合は、データの更新を手動でコミットする必要があります。最終のCOMMIT
操作以降に加えられた変更内容をコミットするには、次のようにSQLJのCOMMIT
文を使用します。
#sql { COMMIT };
最終のCOMMIT
操作以降に加えられた変更内容のロールバックを行うには、次のようにSQLJのROLLBACK
文を使用します。
#sql { ROLLBACK };
注意:
-
自動コミットを使用可能にしたときは、
COMMIT
コマンドやROLLBACK
コマンドを使用しないでください。使用した場合は、意図しない動作またはSQL例外が発生します。 -
指定したセーブポイントをロールバックすることもできます。「セーブポイントの使用」を参照してください。
-
Oracle SQL構文のすべてのDDL文には、暗黙的な
COMMIT
操作が組み込まれています。SQLJには、この機能はありません。そのような文は標準のOracle SQL規則に従います。 -
自動コミット・モードがオフの場合に、クライアント・アプリケーションから接続コンテキスト・インスタンスをクローズすると、最後の
COMMIT
操作後に行った変更がコミットされます(ただし、接続コンテキスト・インスタンスをKEEP_CONNECTION
でクローズした場合を除きます)。詳細は、「共有接続の終了」を参照してください。
4.5.6 イテレータおよび結果セットに対するコミットおよびロールバックの影響
COMMIT
およびROLLBACK
操作は、オープンしている結果セットとイテレータには反映されません。結果セットおよびイテレータはオープンしたままになります。通常それぞれの内容はSELECT
文を実行したときのデータベースの状態が引き続き反映されています。
注意:
イテレータ・クラスをsensitivity=SENSITIVE
と宣言している場合は例外です。この場合、イテレータをウィンドウ・サイズの外部でスクロールすると、基になる結果セットへの変更が表示されます。スクロール可能なイテレータの詳細は、「スクロール可能なイテレータ」を参照してください。基になるスクロール可能な結果セットの詳細は、『Oracle Database JDBC開発者ガイド』を参照してください。
UPDATE
、INSERT
およびDELETE
文をSELECT
文の後に実行した場合も同じです。これらの文を実行しても、オープンしている結果セットとイテレータの内容は変わりません。
SELECT
、UPDATE
およびCOMMIT
の各操作をこの順に実行した場合を考えてください。UPDATE
およびCOMMIT
を実行しても、sensitiveではない結果セットやイテレータの内容は、SELECT
文で設定されたときの状態のまま変更されません。
さらに、UPDATE
、SELECT
およびROLLBACK
の操作をこの順に実行したとします。SELECT
で移入されたsensitiveでない結果セットやイテレータには、依然として更新データが格納されており、その後に実行されたROLLBACK
の影響は受けません。
4.5.7 セーブポイントの使用
JDBC 3.0の仕様では、セーブポイントのサポートが追加されました。セーブポイントとは、トランザクション全体をロールバックするのではなく、必要に応じてトランザクション内でロールバックできるように定義された位置です。セーブポイントとは、SAVEPOINT
文が出現するトランザクション内の位置です。
Oracle9i データベース リリース2(9.2)のSQLJで、セーブポイントをサポートするためのOracle固有の構文が導入されました。Oracle Database 12c リリース2 (12.2)のSQLJでは、ISO SQLJ規格のセーブポイント構文のサポートが追加されています。
ISO SQLJ規格のセーブポイント構文のサポート
ISO SQLJ規格の構文では、SAVEPOINT
文で文字列リテラルを使用して、セーブポイントの名前を指定します。これを行うには、次の手順を実行します。
#sql { SAVEPOINT savepoint1 };
そのセーブポイントまで変更をロールバックする場合、次のように、後でROLLBACK TO
文にその指定した名前を指定できます。
#sql { ROLLBACK TO savepoint1 };
セーブポイントが不要になった場合、RELEASE SAVEPOINT
文を使用します。
#sql { RELEASE SAVEPOINT savepoint1 };
セーブポイントは、SQLJ実行コンテキストに保存されます。SQLJ実行コンテキストには、これらの3つの文の機能に相当するメソッドがあります。
関連項目:
COMMIT
操作によってトランザクションが終了するため、トランザクション内のセーブポイントもすべて解放されます。
Oracle SQLJのセーブポイント構文
ISO SQLJ規格の構文に加えて、次に示すOracle固有のセーブポイントの構文がサポートされています。Oracle構文では、文字列リテラルではなく、文字列のホスト式が使用されていることに注意してください。
セーブポイントを設定するには、次の構文を使用します。
#sql { SET SAVEPOINT :savepoint };
この例のホスト式、savepoint
は、セーブポイントの名前をJavaのString
で指定する変数です。
セーブポイントまでロールバックするには、次の構文を使用します。
#sql { ROLLBACK TO :savepoint };
セーブポイントを解放するには、次のSQLJ文を使用します。
#sql { RELEASE :savepoint };
注意:
Oracle固有の構文は、下位互換性のために引き続きサポートされています。Oracle構文とISO SQLJ規格の構文の次の相違点に注意してください。
-
Oracle構文は、文字列リテラルではなく、文字列変数をとります。
-
Oracle構文では、
SAVEPOINT
のかわりにSET SAVEPOINT
を使用します。 -
Oracle構文では、
RELEASE SAVEPOINT
のかわりにRELEASE
を使用します。
4.6 概要: 簡単なSQLJコード
これまでに説明したSQLJ実行文の特長と機能について要点を把握するには、簡潔で包括的なプログラムを試してみるのが一番効果的な方法です。ここでは、2つの例を示します。
最初の例では、操作を1つずつ示してから、全体を示します。この例では、SELECT INTO
文を使用して従業員表の2つの列に対して単一行の問合せを実行します。この例を実行する場合は、connect.properties
ファイルのパラメータを、適切なデータベースに接続できる設定に変更する必要があります。
2番目の例は多少複雑です。SQLJのイテレータを使用して複数行問合せを実行します。
必要なクラスのインポート
必要なJDBCまたはSQLJパッケージをすべてインポートします。少なくとも、java.sql
パッケージ内のクラスがいくつか必要です。
import java.sql.*;
java.sql
パッケージ内のクラスを、必ずしもすべて使用するわけではありません。主に使用するクラスとしては、java.sql.SQLException
と、明示的に参照するクラスがあります。たとえば、java.sql.Date
やjava.sql.ResultSet
です。
Oracle
クラスには、次のパッケージが必要です。通常、DefaultContext
オブジェクトをインスタンス化し、デフォルト接続を確立するときに、このクラスを使用します。
import oracle.sqlj.runtime.*;
SQLJのランタイム・クラスをコード中に直接使用する場合は、次のパッケージをインポートします。
import sqlj.runtime.*; import sqlj.runtime.ref.*;
ただし、コード中にSQLJのランタイム・クラスを直接使用しない場合でも、ランタイム・クラスをCLASSPATH
に指定するのみで十分です。
重要なランタイム・クラスとしては、sqlj.runtime
パッケージのResultSetIterator
およびExecutionContext
と、sqlj.runtime.ref
パッケージのDefaultContext
などがあります。
JDBCドライバの登録およびデフォルト接続の設定
デフォルトの接続を設定するには、static Oracle.connect()
メソッドを使用するコンストラクタで、SimpleExample
クラスを宣言します。この結果、Oracle JDBCドライバの登録も行われます。
ここでは、URL、ユーザー名およびパスワードをconnect.properties
ファイルから取得するconnect()
のシグネチャを使用します。このファイルの例は、ORACLE_HOME
/sqlj/demo
ディレクトリおよび「ランタイム接続の設定」にあります。
public class SimpleExample { public SimpleExample() throws SQLException { // Set default connection (as defined in connect.properties). Oracle.connect(getClass(), "connect.properties"); }
例外処理の設定
main()
を作成します。このメソッドからSimpleExample
コンストラクタをコールし、try/catch
ブロックをセットアップします。このブロックでは、runExample()
メソッドにより発生したSQL例外を処理します。このアプリケーションの実際の処理は、このメソッドが行います。
... public static void main (String [] args) { try { SimpleExample o1 = new SimpleExample(); o1.runExample(); } catch (SQLException ex) { System.err.println("Error running the example: " + ex); } } ...
接続を終了するには、try/catch
ブロックをfinally
句の内部に使用します。SQL例外の場合にfinally
句がtry/catch
ブロック内部に使用されていないことが前提です。
finally { try { Oracle.close(); } catch(SQLException ex) {...} }
ホスト変数のセットアップ、SQLJ句の実行、結果の処理
次の処理を行うrunExample()
メソッドを作成します。
-
main()
メソッドに対してSQL例外をスローし、処理させます。 -
Javaのホスト変数を宣言します。
-
SQLJ句を実行します。Javaのホスト変数が埋込み
SELECT
文にバインドされ、データがホスト変数に取り込まれます。 -
結果を出力します。
このメソッドのコードは次のようになります。
void runExample() throws SQLException { System.out.println( "Running the example--" ); // Declare two Java host variables-- Float salary; String empname; // Use SELECT INTO statement to execute query and retrieve values. #sql { SELECT first_name, salary INTO :empname, :salary FROM employees WHERE employee_id = 7499 }; // Print the results-- System.out.println("Name is " + empname + ", and Salary is " + salary); } } // Closing brace of SimpleExample class
前述のコード例では、Javaのホスト変数としてsalary
とempname
が宣言されています。その次のSQLJ句の処理では、employees
表のfirst_name
列とsalary
列から選択されたデータが、ホスト変数に格納されます。最後に、salary
とempname
の値が出力されます。
このSELECT
文ではemployees
表から選択できる行は1行のみで、WHERE
句のemployee_id
列が表の主キーになっているためです。
SELECT INTOを使用した単一行問合せの例
ここでは、前に1つずつ順を追って説明した内容をSimpleExample
クラスを使用して総復習します。次の例は単一行問合せの例であるため、イテレータは使用しません。
// Import SQLJ classes: import sqlj.runtime.*; import sqlj.runtime.ref.*; import oracle.sqlj.runtime.*; // Import standard java.sql package: import java.sql.*; public class SimpleExample { public SimpleExample() throws SQLException { // Set default connection (as defined in connect.properties). Oracle.connect(getClass(), "connect.properties"); } public static void main (String [] args) throws SQLException { try { SimpleExample o1 = new SimpleExample(); o1.runExample(); } catch (SQLException ex) { System.err.println("Error running the example: " + ex); } } finally { try { Oracle.close(); } catch(SQLException ex) {...} } void runExample() throws SQLException { System.out.println( "Running the example--" ); // Declare two Java host variables-- Float salary; String empname; // Use SELECT INTO statement to execute query and retrieve values. #sql { SELECT first_name, salary INTO :empname, :salary FROM employees WHERE employee_id = 7499 }; // Print the results-- System.out.println("Name is " + empname + ", and Salary is " + salary); } }
名前付きイテレータの設定
次の例は、前の例がベースになっていますが、それに加えて名前付きイテレータを使用し、複数行問合せを実行します。
最初に、イテレータ・クラスを宣言します。NULL
値が戻される可能性がある場合は、基本型int
とfloat
ではなくて、オブジェクト型Integer
とFloat
を使用してください。
#sql iterator EmpRecs( int empno, // This column cannot be null, so int is OK. // (If null is possible, use Integer.) String ename, String job, Integer mgr, Date hiredate, Float sal, Float comm, int deptno);
次にEmpRecs
クラスをインスタンス化し、問合せ結果を移入します。
EmpRecs employees; #sql employees = { SELECT employee_id, first_name, job_id, manager_id, hire_date, salary, commission_pct, department_tno FROM employees };
次に、イテレータのnext()
メソッドで結果を出力します。
while (employees.next()) { System.out.println( "Name: " + employees.first_name() ); System.out.println( "EMPNO: " + employees.employee_id() ); System.out.println( "Job: " + employees.job_id() ); System.out.println( "Manager: " + employees.manager_id) ); System.out.println( "Date hired: " + employees.hire_date() ); System.out.println( "Salary: " + employees.salary() ); System.out.println( "Commission: " + employees.commission_pct() ); System.out.println( "Department: " + employees.department_no() ); System.out.println(); }
最後に、イテレータを終了します。
employees.close();
名前付きイテレータを使用した複数行問合せの例
この例では、名前付きイテレータを使用して複数行問合せを行い、従業員表から複数のデータ列を選択します。
この例は、名前付きイテレータを使用していることを除けば、前に示した単一行問合せの例と概念はほとんど同じです。
// Import SQLJ classes: import sqlj.runtime.*; import sqlj.runtime.ref.*; import oracle.sqlj.runtime.*; // Import standard java.sql package: import java.sql.*; // Declare a SQLJ iterator. // Use object types (Integer, Float) for mgr, sal, And comm rather // than primitive types to allow for possible null selection. #sql iterator EmpRecs( int empno, // This column cannot be null, so int is OK. // (If null is possible, Integer is required.) String ename, String job, Integer mgr, Date hiredate, Float sal, Float comm, int deptno); // This is the application class. public class EmpDemo1App { public EmpDemo1App() throws SQLException { // Set default connection (as defined in connect.properties). Oracle.connect(getClass(), "connect.properties"); } public static void main(String[] args) { try { EmpDemo1App app = new EmpDemo1App(); app.runExample(); } catch( SQLException exception ) { System.err.println( "Error running the example: " + exception ); } } finally { try { Oracle.close(); } catch(SQLException ex) {...} } void runExample() throws SQLException { System.out.println("\nRunning the example.\n" ); // The query creates a new instance of the iterator and stores it in // the variable 'employees' of type 'EmpRecs'. SQLJ translator has // automatically declared the iterator so that it has methods for // accessing the rows and columns of the result set. EmpRecs employees; #sql employees = { SELECT employee_id, first_name, job_id, manager_id, hire_date, salary, commission_pct, department_no FROM employees }; // Print the result using the iterator. // Note how the next row is accessed using method 'next()', and how // the columns can be accessed with methods that are named after the // actual database column names. while (employees.next()) { System.out.println( "Name: " + employees.first_name() ); System.out.println( "EMPNO: " + employees.employee_id() ); System.out.println( "Job: " + employees.job_id() ); System.out.println( "Manager: " + employees.manager_id() ); System.out.println( "Date hired: " + employees.hire_date() ); System.out.println( "Salary: " + employees.salary() ); System.out.println( "Commission: " + employees.commission_pct() ); System.out.println( "Department: " + employees.department_no() ); System.out.println(); } // You must close the iterator when it's no longer needed. employees.close() ; } }
4.7 Oracle固有コード生成(プロファイルなし)
このマニュアルでは、全体にわたって一般的かつ標準的なSQLJランタイム・レイヤーおよびSQLJプロファイルについて説明しています。ただし、Oracle SQLJ実装では、SQLJランタイムをコールするISO SQLJ規格コードではなく、Oracle JDBCドライバを直接コールするOracle固有コードがデフォルトで生成されます。Oracle固有コード生成の場合、プロファイル・ファイルはなく、SQLJランタイム・レイヤーの役割はプログラム実行時に大幅に縮小されます。Oracle固有コードでは、すべてのOracle固有の拡張機能がサポートされています。
コード生成は、SQLJトランスレータの-codegen
オプションによって決まります。Oracle固有コード生成のデフォルト設定は、-codegen=oracle
です。また、ISO SQLJ規格に従ったコード生成を行うために、-codegen=iso
を設定することもできます。
この項の内容は次のとおりです。
4.7.1 Oracle固有コード生成用環境の要件
Oracle固有コード生成を使用する場合、次の環境の要件に留意してください。
-
Oracle固有コード生成にはJDBC文のキャッシング機能が必要であるため、Oracle11g以降のバージョンのJDBCドライバを使用する必要があります。
-
汎用SQLJランタイム・ライブラリ
runtime
は、Oracle固有コード生成ではサポートされていません。次のいずれかのOracle SQLJランタイム・ライブラリをCLASSPATH
に指定する必要があります。-
runtime12.jar
-
runtime12ee.jar
-
4.7.2 Oracle固有コード生成でのコード上の考慮事項と制限事項
Oracle固有コード生成が使用されるSQLJアプリケーションのコーディング時には、次のプログラミング上の考慮事項および制限に注意してください。
-
デフォルト以外の文キャッシュ・サイズを使用する場合は、Oracleカスタマイザの
stmtcache
オプションが使用できないため、コードに適切なメソッド・コールを記述する必要があります。 -
同じアプリケーションに、Oracle固有生成コードとISO SQLJ規格生成コードを混在しないでください。ただし、Oracle固有コードおよびISO SQLJ規格コードが同じ接続を共有する必要がある場合は、次のいずれかを実行します。
-
Oracle固有コードおよびISO標準コードが、必ず異なるSQLJ実行コンテキスト・インスタンスを使用するようにします。SQLJ実行コンテキストの詳細は、「実行コンテキスト」を参照してください。
-
トランザクション境界(手動の
COMMIT
文またはROLLBACK
文)を2種類のコードの間に配置します。
コードの混在に関するこの制限事項は、あるセッションで実行中のすべてのJavaコードが同じJDBC接続とSQLJ接続コンテキストを使用するので、サーバー側のコードで特に重要になります。
-
-
データベースから値が戻されるとき、パラメータ表現での副作用に頼らないでください。Oracle固有コード生成では、
OUT
パラメータ、IN OUT
パラメータ、SELECT INTO
変数、またはSQL文の戻り引数を評価するための一時変数が作成されません。たとえば、次のような文は使用しないでください。
#sql { SELECT * FROM EMPLOYEES INTO :(x[i++]), :(f_with_sideffect()[i++]), :(a.b[i]) };
または
#sql x[i++] = { VALUES f(:INOUT (x[i++]), :OUT (f_with_sideffect())) };
引数の評価は、生成コードの適切な場所で実行されます。これによって、ISO SQLJ規格に従って評価が実施される場合と、動作が異なることになります。
-
Oracleオブジェクト機能の型マップは、対応するJavaクラスで
java.sql.SQLData
インタフェースが実装されることを前提としています。Oracleオブジェクト機能の型マップを使用する場合、イテレータ宣言と接続コンテキスト宣言で同じ型マップを指定する必要があります。これは、with
句で指定します。たとえば、接続コンテキスト・クラスを宣言する場合、次のようにします。
#sql context TypeMapContext with (typeMap="MyTypeMap");
また、この接続コンテキスト・クラスのインスタンスを使用するSQLJ文からイテレータ・インスタンスを移入するには、次のようにします。
TypeMapContext tmc = new TypeMapContext(...); ... MyIterator it; #sql [tmc] it = ( SELECT pers, addr FROM tab WHERE ...);
イテレータ宣言では同じ型マップを指定する必要があります。次のようにします。
#sql iterator MyIterator with (typeMap="MyTypeMap") (Person pers, Address addr);
関連項目:
注意:
この制限事項の理由は、Oracle固有コード生成の場合、イテレータを取得するすべてのメソッドが変換時に完全にOracle JDBCコールとして生成されているためです。適切なコールを生成するには、イテレータがある特定の型マップで使用されるかどうかをSQLJトランスレータで把握する必要があります。
4.7.3 Oracle固有コード生成時のSQLJ使用方法の変更
以前にOracleカスタマイザのオプションとしてのみ使用可能なオプションで、Oracle固有コード生成でも便利なオプションがあります。プロファイルのカスタマイズはOracle固有コード生成には適用できないため、これらのオプションは他の方法で使用できるようになりました。
文キャッシュのサイズを変更したり、Oracle固有コードの生成時に文のキャッシングを無効化するには、カスタマイザのstmtcache
オプションではなく、メソッド・コールをコードに使用します。sqlj.runtime.ref.DefaultContext
クラスと同様に、宣言するすべての接続コンテキスト・クラスには、現在次のstaticメソッドがあります。
-
setDefaultStmtCacheSize(int)
-
int getDefaultStmtCacheSize()
また、次のインスタンス・メソッドがあります。
-
setStmtCacheSize(int)
-
int getStmtCacheSize()
デフォルトで、文のキャッシングを使用できます。
関連項目:
さらに、次のオプションは、Oracleカスタマイザのオプションと同様に、フロントエンドのOracle SQLJトランスレータとして使用できます。
-
-optcols
: パフォーマンスが最適化されるようにイテレータ列型およびサイズ定義を有効化するためのオプション。 -
-optparams
: JDBCリソース割当てが最適化されるようにパラメータ・サイズ定義を有効化するためのオプション。このオプションは、optparamdefaults
と併用されます。 -
-optparamdefaults
: 特定のデータ型に対してパラメータ・サイズのデフォルトを設定するためのオプション。このオプションは、optparams
と併用されます。 -
-fixedchar
:WHERE
句に関して、空白埋めを考慮したCHAR
比較を有効にするためのオプション。
以下の点に注意します。
-
オンラインのセマンティクス・チェックを使用している場合のみ(SQLJトランスレータの
-user
、-password
および-url
オプションを使用して、変換時にデータベース接続を要求している場合)、-optcols
オプションを使用します。 -
-optcols
、-optparams
および-optparamdefaults
オプションの機能とデフォルト値は、カスタマイザのオプションと同じです。
4.7.4 Oracle固有コード生成のメリットとデメリット
Oracle固有コード生成を使用すると、ISO標準コード生成と比較して次のメリットがあります。
-
アプリケーションの実行がより効率的になります。コードではJDBC Application Programming Interface (API)を直接コールするため、ランタイムのパフォーマンスがただちにJDBCレベルになります。中間的なSQLJランタイム・レイヤーの役割は、プログラム実行時に大幅に縮小されます。
-
アプリケーションのサイズが小さくなります。
-
プロファイル・ファイル(
.ser
)は生成されません。変換されたアプリケーションをデータベースにロードするか、別のシステムに移植すると、コンポーネントが少ないため、これは特に便利です。 -
プロファイルのカスタマイズ処理がないので、変換が高速になります。
-
実行時に、Oracle SQLJランタイムとOracle JDBCドライバは同じ文キャッシュ・リソースを使用するため、Oracle SQLJランタイムとOracle JDBCドライバ間のリソースのパーティション化が不要です。
-
プロファイル・ファイルではなくJavaクラス・ファイルにSQL固有情報があると、潜在的なセキュリティの問題を回避できます。
-
静的SQLコードの実行のために考慮されている拡張機能など、将来サポートされるOracle JDBCのパフォーマンス強化のメリットを活用するために、コードを再度記述する必要はありません。Oracle SQLJトランスレータの将来のリリースではこれが自動的に処理できるようになります。
-
ブラウザ環境に完全な移植性が備わるので、Javaリフレクションが実行時に使用されることが少なくなります。
ただし、いくつかのデメリットがあります。
-
Oracle固有の生成コードは、汎用JDBCプラットフォームには移植できません。
-
プロファイル固有の機能は使用できません。たとえば、後からOracleカスタマイザ・ハーネスの
-debug
、-verify
および-print
オプションを使用してカスタマイズを実行することができません。
4.8 ISO標準コード生成
この項の内容は次のとおりです。
4.8.1 ISO標準コード生成用環境の要件
Oracle SQLJ実装では、デフォルトで、SQLJランタイムをコールするISO SQLJ規格コードを生成するのではなく、Oracle JDBCドライバを直接コールするOracle固有コードを生成します。ISO標準コード生成の一般的な環境設定を次に示します。
-
SQLJコード生成:
-codegen=iso
-
SQLJ変換ライブラリ:
translator.jar
-
SQLJランタイム・ライブラリ: JDK 6またはJDK 7と、Oracle Database 12c リリース2 (12.2)を含む
runtime12.jar
-
JDBCドライバ: Oracle Database 12c リリース2 (12.2)の
ojdbc6.jar
またはojdbc7.jar
-
JDKバージョン: JDK 6またはJDK 7
4.8.2 SQLJトランスレータとSQLJランタイム
ここでは、ISO標準コード生成の場合に見られるOracle SQLJ実装の特徴について説明します。
-
SQLJトランスレータ:
.java
ファイルに加え、トランスレータによってISO標準コード生成用に1つ以上のSQLJプロファイルも生成されます。これらのプロファイルには、埋込みSQL操作についての情報が含まれます。SQLJでは、その後Javaコンパイラが自動的に起動され、.java
ファイルから.class
ファイルが生成されます。関連項目:
-
SQLJランタイム: ISO標準コード生成の場合、SQLJランタイムによって、JDBCドライバを介してデータベースにアクセスすることで、SQL操作の必要な処理が実装されます。汎用のISO SQLJ標準では、SQLJランタイムはJDBCドライバを使用してデータベースにアクセスする必要はありません。
関連項目:
トランスレータとランタイムに加え、カスタマイザと呼ばれるコンポーネントも役割を担います。カスタマイザを使用すると、特定のデータベースの実装、ベンダー固有の機能およびデータ型に合わせてSQLJプロファイルが調整されます。デフォルトでは、ISO標準コードに対して、SQLJフロントエンドがOracleカスタマイザを起動し、Oracle DatabaseインスタンスとOracle固有の機能およびデータ型に合わせてプロファイルを調整します。
変換時にOracleカスタマイザを使用すると、アプリケーションの実行時にSQLJランタイムおよびOracle JDBCドライバが必要になります。
注意:
Oracle Database 10g リリース1以降、Oracle JDBCドライバのみがSQLJでサポートされています。
4.8.3 SQLJプロファイル
ISO標準コード生成の場合、SQLJプロファイルとは、SQLJトランスレータによって生成される、シリアライズされたJavaリソースまたはクラスのことで、埋込みSQL文に関する詳細情報が記述されています。トランスレータはこれらのプロファイルを作成します。次に、トランスレータのオプション設定に従って、プロファイルをシリアライズしてバイナリ・リソース・ファイルに出力するか、.class
ファイルに出力します。
この項の内容は次のとおりです。
4.8.3.1 プロファイルの概要
ISO標準コードでは、SQLJ実行文に埋込みSQL操作を実装する場合にSQLJプロファイルを使用します。プロファイルの内容は、SQL操作およびアクセスするデータの型とモードに関する情報です。プロファイルはエントリの集合であり、各エントリが1つのSQL操作に対応します。各エントリでは、対応するSQL操作が十分に指定され、この指示の処理時に使用される各パラメータが記述されています。
SQLJでは、アプリケーション内の接続コンテキスト・クラスごとにプロファイルが生成され、各接続コンテキスト・クラスはデータベース操作で使用する特定のSQLエンティティのセットに対応しています。デフォルトの接続コンテキスト・クラスが1つあり、さらにクラスを宣言できます。ISO SQLJ規格では、プロファイルを標準の形式および内容にする必要があります。そのため、アプリケーションでベンダー固有の拡張機能を使用する場合は、プロファイルのカスタマイズが必要になります。デフォルトの設定では、これが自動的に行われ、Oracle固有の拡張機能を使用するようにプロファイルがカスタマイズされます。
プロファイルをカスタマイズすると、次の利点があります。
-
ベンダー固有のデータ型とSQL構文を使用できます。たとえば、Oracleカスタマイザを使用して、変換済SQLJコードのJDBC標準
PreparedStatement
メソッド・コールをOraclePreparedStatement
メソッド・コールにマッピングすることにより、Oracle拡張型がサポートされます。 -
ベンダー固有の最適化によってパフォーマンスを向上できます。
注意:
-
デフォルトの設定では、SQLJプロファイルの拡張子が
.ser
になりますが、すべての.ser
ファイルがプロファイルであるとは限りません。その他のシリアライズされたオブジェクトにもこの拡張子を使用できるため、SQLJプログラム・ユニットでプロファイル以外のシリアライズされたオブジェクトを使用できます。必要に応じて、プロファイルは.ser
ファイルではなく.class
ファイルにも変換できます。 -
ソース・コード中にSQLJ実行文を記述しないかぎり、SQLJプロファイルは生成されません。
4.8.4 SQLJ変換処理
ISO標準コード生成(-codegen=iso
)の場合は、トランスレータがSQLJソース・コードを処理し、SQL操作をSQLJランタイム・コールに変換し、Java出力コードと1つ以上のSQLJプロファイルを生成します。プロファイルは、ソース・コード中の接続コンテキスト・クラスごとに別個に生成されますが、これは操作で使用される相互に関係するSQLエンティティのセットごとに、通常は異なる接続コンテキスト・クラスが使用されるためです。
生成されたJavaコードは.java
出力ファイルに保存されます。次の内容がこのファイルに出力されます。
-
.sqlj
ソース・ファイル内のクラス定義とJavaコード。 -
SQLJイテレータおよび接続コンテキストの宣言に基づいて生成されたクラス定義。
関連項目:
-
専用クラス(プロファイルキー・クラス)のクラス定義。SQLJでは、このクラスは、プロファイルとともに生成され、使用されます(ISO標準SQLJコード生成のみ)。
-
SQLJランタイムへのコール。埋込みSQL操作のアクションを実装します。
生成されたプロファイルには、実行するアクション、操作するデータ型、アクセスする表など、SQLJソース・コード中のすべての埋込みSQL文に関する情報が格納されます。アプリケーションを実行すると、SQLJランタイムはプロファイルにアクセスしてSQL操作を取り出し、JDBCドライバに渡します。
プロファイルは、デフォルトでシリアライズ・リソース・ファイル(.ser
)に出力されますが、オプションで、変換時に.ser
ファイルを.class
ファイルに変換できます。
生成されたJavaソース・ファイルがコンパイルされ、Javaの.class
ファイルが生成されます。これには、定義される各クラス、各SQLJ宣言、プロファイルキー・クラスに対する.class
ファイルが含まれます。次に、JVMでOracleカスタマイザまたは指定したその他のカスタマイザを起動して、生成したプロファイルをカスタマイズします。
関連項目:
SQLJの一般的な注意
ISO固有のコード生成でSQLJアプリケーションを変換および実行する場合は、次の点を考慮してください。
-
Oracle固有コード生成では、コマンドラインで既存の
.java
ファイルをコンパイルして、型変換可能にすることに加え、次を実行する必要があります。-
既存のプロファイルのカスタマイズ
-
プロファイルを含むJava Archive(JAR)ファイルのカスタマイズ
-
-
ソース・コードにSQLJ実行可能文が含まれる場合のみ、SQLJによってプロファイルおよびプロファイルキー・クラスが生成されます。
-
変換時にOracleカスタマイザを使用する場合は、アプリケーションの実行時にOracle SQLJランタイムおよびOracle JDBCドライバが必要になります(コードでOracle固有の機能を使用しない場合でも必要です)。変換時に
-profile=false
を指定して、Oracle固有のカスタマイズを省略すると、これを回避できます。
4.8.5 トランスレータ入出力の概要
Oracle固有のコード生成の場合に、SQLJトランスレータが入力としてとるもの、出力として生成するもの、およびその出力先について説明しました。ここでは、同じ項目について、ISO標準のコード生成の観点で説明します。
関連項目:
4.8.5.1 トランスレータへの入力
Oracle固有のコード生成の場合と同様に、SQLJトランスレータは、入力として1つ以上の.sqlj
ソース・ファイルをとります。このソース・ファイルはコマンドラインで指定できます。メインの.sqlj
ファイルの名前は、そこで定義されるPublicクラス(ある場合)または定義された最初のクラスに基づきます。
関連項目:
4.8.5.2 トランスレータの出力
変換処理では、アプリケーション内の.sqlj
ファイルごとにJavaソース・ファイルが生成されます。また、ISO標準コード生成の場合、アプリケーションのプロファイルは、1つ以上生成されます(ソース・コードにSQLJ実行文があるとき)。
SQLJでは、次のJavaソース・ファイルとアプリケーション・プロファイルが生成されます。
関連項目:
-
Oracle固有のコード生成の場合と同様に、Javaソース・ファイルは
.sqlj
ファイルと同じベース名の.java
ファイルです。 -
アプリケーションのプロファイル・ファイル(ある場合)には、SQLJアプリケーションのSQL操作に関する情報が含まれます。プロファイルは、アプリケーションで使用する接続クラスごとに1つ生成されます。プロファイルの名前は、メインの
.sqlj
ファイルと同じベース名になり、次の拡張子が付きます。_SJProfile0.ser _SJProfile1.ser _SJProfile2.ser ...
たとえば、
MyClass.sqlj
の場合は、トランスレータによって次のプロファイル・ファイルが生成されます。MyClass_SJProfile0.ser
.ser
ファイル拡張子は、プロファイルがシリアライズされていることを示します。.ser
ファイルはバイナリ・ファイルです。注意:
トランスレータ・オプション
-ser2class
を指定すると、トランスレータによって生成されるプロファイル・ファイルが.ser
ファイルではなく.class
ファイルになります。ファイル名の拡張子以外の部分は、同じになります。
Oracle固有のコード生成のコンパイル手順と同様に、Javaソース・ファイルを複数のクラス・ファイルにコンパイルすると、.sqlj
ソース・ファイルに定義されたクラスごとに、1つの.class
ファイルが生成されます。ただし、ISOコード生成の場合は、トランスレータがSQL操作を実装するためにプロファイルとともに生成して使用するプロファイルキー・クラスと呼ばれるクラスに対しても、1つの.class
ファイルが生成されます。SQLJのイテレータまたは接続コンテキストを宣言した場合は、さらに.class
ファイルが生成されます。また、Oracle固有コード生成と同様に、コード中に内部クラスまたは無名クラスが宣言されている場合は、それらのクラスごとに.class
ファイルが個別に生成されます。
関連項目:
これらの.class
ファイルには、次の名前が付けられます。
-
Oracle固有のコード生成と同様に、定義された各クラスのクラス・ファイル名は、クラス名および
.class
拡張子で構成されます。 -
トランスレータで生成されたプロファイルキー・クラスは、メインの
.sqlj
ファイルのベース名と次の文字列から構成される名前が付けられます。_SJProfileKeys
つまり、クラス・ファイルの拡張子は、次のような名前になります。
_SJProfileKeys.class
たとえば、
MyClass.sqlj
の場合は、トランスレータとコンパイラによって次のクラス・ファイルが生成されます。MyClass_SJProfileKeys.class
-
Oracle固有のコード生成と同様に、トランスレータを実行すると、イテレータ・クラスと接続コンテキスト・クラスに、宣言方法に従って名前が付けられます。
カスタマイズ処理によってプロファイルが変更されますが、追加出力はありません。
注意:
必ずしもSQLJプロファイルまたはプロファイルキー・クラスを直接参照する必要はありません。これらは、すべて自動的に処理されます。
4.8.6 SQLJランタイム処理
ここでは、プログラム実行時のISO標準コードに対するランタイム処理について説明します。
ISO標準SQLJアプリケーションの場合は、SQLJランタイムがプロファイルを読み取って接続プロファイルを作成し、接続プロファイルにデータベース接続情報が組み込まれます。アプリケーションでデータベースへのアクセスが必要になると、そのつど次に示す処理が発生します。
-
SQLJで生成したアプリケーション・コードは、SQLJで生成したプロファイルキー・クラスのメソッドを使用して接続プロファイルにアクセスし、関係するSQL操作を読み取ります。アプリケーション内のSQLJ実行文とプロファイル内のSQL操作はマッピングされています。
-
SQLJで生成したアプリケーション・コードからSQLJランタイムをコールします。SQL操作がプロファイルから読み込まれます。
-
SQLJランタイムがJDBCドライバをコールして、SQL操作をドライバに渡します。
-
SQLJランタイムが入力パラメータをJDBCドライバに渡します。
-
JDBCドライバがSQL操作を実行します。
-
戻り値がある場合は、データベースがデータをJDBCドライバに送ります。このデータはドライバからSQLJランタイムに送られ、アプリケーションで使用できるようになります。
注意:
入力パラメータを渡すことは、入力パラメータをバインドするまたはホスト式をバインドするとも言います。ホスト変数、ホスト式、バインド変数およびバインド式という用語はすべて、SQL操作の入力または出力として使用されるJava変数または式を説明するために使用されます。
4.8.7 デプロイメント例
次の方法でOracle固有のSQLJコードを実行する方法について説明しました。
-
アプレットから
-
サーバー内で(SQLJトランスレータもサーバーで実行できます)
アプレットからISO標準コードを実行する際に、いくつかの考慮事項があります。
関連項目:
-
次のSQLJランタイム・パッケージはすべて、アプレットとともにパッケージ化する必要があります。次のパッケージを含めます。
sqlj.runtime sqlj.runtime.ref sqlj.runtime.profile sqlj.runtime.profile.ref sqlj.runtime.error
Oracle独自のカスタマイズを行った場合は、次のパッケージも含める必要があります。
oracle.sqlj.runtime oracle.sqlj.runtime.error
これらのパッケージは、Oracleインストールによって、
ORACLE_HOME
/lib
ディレクトリのランタイム・ライブラリの中の1つに組み込まれています。 -
Netscape Navigator 4.xなどの一部のブラウザでは、プロファイル用のSQLJシリアル化オブジェクト・ファイルの拡張子である、
.ser
拡張子の付いたリソース・ファイルをサポートしていません。ただし、Sun MicrosystemsのJavaプラグインでは.ser
ファイルをサポートしています。Oracle SQLJ実装では、このプラグインを使用する以外の方法として、
.ser
ファイルを.class
ファイルに変換するための-ser2class
オプションを使用する方法があります。注意:
この考慮事項は、プロファイルが生成されないデフォルトのOracle固有コード生成には適用されません。
-
Oracle固有の機能を使用するアプレットでは、Oracle SQLJランタイムを起動する必要があります。Oracle SQLJランタイムは、
oracle.sqlj.*
下のSQLJランタイム・ライブラリ・ファイル内のクラスで構成されます。Oracle SQLJruntime.jar
ライブラリでは、Java Reflection API(java.lang.reflect.*
)が必要です。大半のブラウザでは、Reflection APIをサポートしていなかったりセキュリティ上の制約があるのに対し、Sun社のJavaプラグインの場合はReflection APIに対するサポートが提供されています。ISO標準のコード生成の場合、次のSQLJ言語の機能では、使用しているSQLJランタイムのバージョンに関係なく、常にJava Reflection APIが必要となります。
-
CAST
文 -
SQLJイテレータのインスタンスとしてのデータベースから取得される
REF CURSOR
パラメータまたはREF CURSOR
列 -
java.sql.Ref
、Struct
、Array
、Blob
またはClob
オブジェクトの取得 -
oracle.sql.ORAData
またはjava.sql.SQLData
インタフェースを実装するJavaクラスのインスタンスとしてのSQLオブジェクトの取得注意:
-
ただし、ISOと完全に互換性のあるモードでSQLJを使用する場合は例外です。つまり、SQLJをJ2EEに準拠した環境で使用する場合、SQLJ
runtime12ee.jar
ライブラリでプログラムを変換および実行する場合、およびISOで指定したように接続コンテキストの型マップを採用する場合です。この場合、java.sql.Ref
、Struct
、Array
、Blob
、Clob
およびSQLData
のインスタンスは、リフレクションを使用せずに取得されます。 -
Oracle固有コード生成を使用すると、前述のすべてのインスタンスでのリフレクションの使用を削減します。
-
-
4.9 Oracle固有コード生成とISO標準コード生成との違い
Oracle SQLJの実装により、Oracle固有コード生成が可能になり、Oracle JDBCコールがコード内に直接生成されます。これはデフォルトの動作です。Oracle固有コード生成の場合、次の点に注意する必要があります。
-
プロファイル・ファイルがないため、変換時のカスタマイズ処理もありません。
-
変換されたコード内に、SQLJランタイム・コールではなくJDBCコールが直接生成されるため、実行時にSQL操作はSQLJランタイム・レイヤーを経由する必要がありません。
4.10 ネーミングの要件および制限事項
ネーミング要件、ネーミング制限および予約語については、次の4点を考慮する必要があります。
-
Javaのネームスペース。ローカル変数とクラスの名前については、SQLJ固有の制限もあります。
-
SQLJのネームスペース
-
SQLのネームスペース
-
ソース・ファイル名
この項の内容は次のとおりです。
4.10.1 Javaのネームスペース: ローカル変数およびクラスのネーミングに関する制限事項
Javaのネームスペースは、Javaのクラスやローカル変数のネーミングなど、標準Javaのすべての文および宣言に適用されます。標準Javaのネーミングに関するすべての制限が適用されるため、Javaの予約語は使用しないでください。
また、ローカル変数とクラスのネーミングには、SQLJ固有の制限も若干伴います。
注意:
ホスト変数名固有の制約については、「ホスト式の制限事項」を参照してください。
ローカル変数のネーミングに関する制限
ローカル変数のネーミングの際は、SQLJトランスレータの一部の機能に起因する制限が若干伴います。SQLJトランスレータは各SQLJ実行文を文ブロックに置き換えますが、このブロックでは、次のように標準構文に基づくSQLJ実行文が使用されます。
#sql { SQL operation };
SQLJでは、生成された文ブロック内に一時変数を宣言できます。この一時変数の名前には、次の接頭辞が付きます。
__sJT_
注意:
アンダースコアが先頭に2つ、末尾に1つ付きます。
SQLJで生成した文ブロックでは、次のような宣言が使用されます。
int __sJT_index; Object __sJT_key; java.sql.PreparedStatement __sJT_stmt;
文字列__sJT_
は、SQLJで生成される変数名の接頭辞として予約されています。SQLJのプログラミングの際は、この文字列を次の名前の接頭辞としては使用しないでください。
-
SQL実行文を含むブロックで宣言した変数名
-
SQL実行文を含むメソッドのパラメータ名
-
SQL実行文を含むクラスのフィールド名、あるいはサブクラスまたは被包含クラスにSQL実行文があるクラスのフィールド名
クラスのネーミングに関する制限
SQLJアプリケーションのクラスのネーミングには、次のような制限が伴います。
-
SQLJの内部クラスと競合する可能性のあるクラス名は宣言しないでください。具体的には、SQLJアプリケーション内の既存クラスの名前が
a
の場合、最上位クラスに次の形式の名前を付けることはできません。a_SJb
a
とb
は正当なJava識別子です。たとえば、ファイル
Foo.sqlj
内のアプリケーション・クラスがFoo
である場合、SQLJはFoo_SJProfileKeys
というプロファイルキー・クラスを生成します。この名前と競合するクラス名は宣言しないでください。 -
SQLJ実行文を含むクラスの名前が、アプリケーションで使用されるJava型を格納するどのパッケージの名前の先頭部分とも同じにならないようにしてください。たとえば、
java
、sqlj
およびoracle
(大/小文字の区別あり)は、クラス名としては使用しないでください。また、SQLJ文に使用するホスト変数の型がabc.def.MyClass
である場合、このホスト変数を使用するクラスの名前にはabc
を使用できません。こうした制限を回避するには、Javaのネーミング規則に従い、パッケージ名の先頭を小文字にし、クラス名の先頭を大文字にすることをお薦めします。
4.10.2 SQLJのネームスペース
SQLJのネームスペースは、#sql
クラス宣言と#sql
実行文の中カッコの外側の部分です。
注意:
イテレータ列のネーミングに伴う特別な制限については、「名前付きイテレータの使用」を参照してください。
SQLJの次の予約語は、宣言する接続コンテキスト・クラスまたはイテレータ・クラスのクラス名として、with
句またはimplements
句で使用できません。イテレータ列の型宣言リストでも使用できません。
-
iterator
-
context
-
with
たとえば、イテレータ・クラスまたはインスタンスの名前をiterator
にしたり、接続コンテキスト・クラスまたはインスタンスの名前をcontext
にしたりしないでください。
ただし、ストアド・ファンクションからの戻り値を格納する変数の名前には、これらのどのワードでも使用できます。
4.10.3 SQLのネームスペース
SQLのネームスペースは、SQLJ実行文の中カッコ内の部分です。このネームスペースには、標準SQLのネーミングに関する制限事項が適用されます。
ただし、ホスト式は、SQLのネームスペースの規則ではなく、Javaのネームスペースの規則に従います。これは、ホスト変数の名前にも、ホスト式の外部のカッコで囲まれたすべての部分にも適用されます。
4.10.4 ファイル名の要件と制限
SQLJソース・ファイルのファイル名拡張子は.sqlj
です。ソース・ファイルでPublicクラスを宣言した場合(最大1つ)、ソース・ファイルのベース名がこのクラス名と一致する必要があります(大/小文字の区別あり)。ソース・ファイルでPublicクラスが宣言されていない場合、ファイル名はJava識別子として有効である必要があるため、ファイル名を最初に定義されたクラスの名前と同じにすることをお薦めします。
たとえば、ソース・ファイルにPublicクラスMySource
が定義されている場合は、次に示すファイル名を付けてください。
MySource.sqlj
注意:
これらのファイル・ネーミング要件は、Java言語仕様(JLS)準拠であり、SQLJ固有のものではありません。これらの要件は、Oracle Database 12c リリース2 (12.2)には直接適用されませんが、それらに従うことをお薦めします。
4.11 中間層のSQLJに関する考慮事項
Oracle9i Application Server Containers for J2EE (OC4J)環境など、中間層でSQLJを実行する場合は特別に考慮する事項があります。
Oracle JDBCドライバでは、oracle.jdbc
パッケージにOracle固有のインタフェースが提供されます。Oracle SQLJライブラリ(runtime12.jar
およびruntime12ee.jar
)は、これらのインタフェースを最大限に活用しますが、これらのライブラリには、Oracle9i Application Serverより前のOracle JDBC実装との互換性がありません。
Oracle9i Application Serverの場合、接続はデータ・ソースを介して確立され、通常は旧式のoracle.jdbc.driver.OracleConnection
クラスではなく、oracle.jdbc.OracleConnection
インタフェースのインスタンスを戻します。これは分散トランザクション(XA)などの特定の接続機能に必要です。このような機能をサポートするには、接続オブジェクトが新規インタフェースを実装する必要があります。
この結果、Oracle9i Application Server中間層環境またはデータ・ソースが使用される他の環境について、次のような処理が必要となります。
-
コードの移植性と柔軟性を最大限にするには、
oracle.jdbc.driver.OracleXXX
型ではなくoracle.jdbc.OracleXXX
型を使用します。 -
カスタムJava型(通常はSQLオブジェクトとコレクション)については、
oracle.sql.ORAData
を実装します。 -
SQLJ
runtime
ライブラリを使用しないでください。かわりに(環境に応じて)runtime12
またはruntime12ee
を使用してください。ランタイム・ライブラリは、Oracle8i Databaseリリース8.1.7などの古いJDBCドライバとの下位互換性があるため、oracle.jdbc.OracleXXX
型ではなく、oracle.jdbc.driver.OracleXXX
型がサポートされています。しかし、なんらかの理由で
runtime
ライブラリを使用する必要がある場合は、変換時にオプション-profile=false
を設定します。その場合、プログラムではOracle固有のカスタマイズが使用されず、そのため、oracle.jdbc.driver.OracleConnection
インスタンスのかわりにoracle.jdbc.OracleConnection
インスタンスを渡しても処理は失敗しません。この状況では、Oracle固有の機能はサポートされません。
データ・ソースを介して取得される接続の管理を容易にしたり、JavaBean (SQLJ JavaServer Pages用)を接続するために、Oracle SQLJ実装では、runtime12ee
ライブラリに多くのAPIが用意されています。
データ・ソースおよび接続JavaBeansへのSQLJサポートの概要は、次の項を参照してください。