「SQL」では、Structured Query Language(SQL)言語およびデータベースによるSQL文の処理方法について説明します。この章では、データベースに格納された手続き型言語/SQL(PL/SQL)またはJavaプログラムがSQLを使用できる仕組みについて説明します。
この章の内容は、次のとおりです。
関連項目:
SQLなどの非手続き型言語では、処理対象のデータ・セットは指定しますが、実行される処理またはその処理の実行方法は指定しません。
手続き型言語プログラムでは、ほとんどの文の実行が、前後の文、およびループまたは条件分岐などの制御構造に依存しますが、このような処理はSQLでは実行できません。手続き型言語と非手続き型言語の相違を例示するために、次のSQL文でemployees
表に問い合せるとします。
SELECT employee_id, department_id, last_name, salary FROM employees;
この文はデータを要求しますが、データにロジックを適用しません。ただし、データ・セットの各従業員が給与および部門の業績に基づく昇給の対象者になるかどうかを判定するアプリケーションが必要であるとします。昇給の必要条件は、従業員が過去5年間に4回以上の昇給を受けていないことです。昇給する場合は、アプリケーションで給与を調整してマネージャに電子メールを送信し、昇給しない場合は、アプリケーションでレポートを更新する必要があります。
この処理を実行するために、条件付きロジックおよびプログラム・フロー制御を必要とする手続き型データベース・アプリケーションでSQLを使用できるようにします。基本的な開発アプローチは次のとおりです。
クライアント側プログラミングを使用して、C、C++またはJavaなどの手続き型言語で記述されたアプリケーションにSQL文を埋め込みます。
ソース・コードにSQL文を配置して、コンパイル前にそのSQL文をプリコンパイラまたはJavaトランスレータに送信できます。または、プリコンパイル手順を省略し、アプリケーションがデータベースと相互作用できるようにJava Database Connectivity(JDBC)またはOracle Call Interface(OCI)などのAPIを使用することもできます。
サーバー側プログラミングを使用して、データベース内に配置するデータ・ロジックを開発します。
アプリケーションは、PL/SQL(「ピーエルシーキューエル」と読みます)またはJavaで記述されたストアド・サブプログラム(プロシージャおよびファンクション)を明示的に起動できます。また、データベースに格納されたプログラム・ユニットの名前を指定し、特定のイベントに応答して起動するトリガーを作成することもできます。
この章では、2番目のアプローチについて説明します。サーバー側プログラミングの主な利点は、データベースに組み込まれた機能を任意の場所にデプロイできることです。指定されたオペレーティング・システム上でタスクを実行するための最善の方法を決定するのは、アプリケーションではなくデータベースです。また、サブプログラムを使用すると、サーバー上にアプリケーション処理を集中化することでスケーラビリティを向上させることができ、また、クライアントでコードを再利用することもできます。サブプログラム・コールは迅速かつ効率的であるため、1回のコールで計算集中型のストアド・サブプログラムを開始し、ネットワーク・トラフィックを軽減できます。
Oracle Databaseにデータ・ロジックを格納するには、次の言語を使用できます。
PL/SQL
PL/SQLは、SQLに対するOracle Databaseの手続きを拡張します。PL/SQLはデータベースに統合されており、すべてのOracle SQL文、関数およびデータ型をサポートします。データベースAPIに記述されたアプリケーションはPL/SQLストアド・サブプログラムを起動し、実行するPL/SQLコード・ブロックをデータベースに送信します。
Java
Oracle Databaseは、Javaアプリケーションの開発、格納およびデプロイもサポートしています。Javaストアド・サブプログラムはデータベースで実行され、中間層で実行されるプログラムからは独立しています。Javaストアド・サブプログラムは、PL/SQLに類似の実行モデルを使用してSQLとインタフェースを確立します。
関連項目:
プリコンパイラおよびAPIでのSQLの埋込みの詳細は、「クライアント側のデータベース・プログラミング」を参照してください
Oracle Databaseアプリケーション開発の概要は、Oracle Database 2日で開発者ガイドを参照してください
プログラミング環境の選択方法の詳細は、Oracle Database開発ガイドを参照してください
PL/SQLは、使用しやすく、SQLとシームレスで、堅牢かつ移植性を備えたセキュアなサーバー側に格納される手続き型言語を提供します。PL/SQLプログラム・ユニットというプロシージャ型スキーマ・オブジェクトを使用してデータベースにアクセスし、データを処理できます。
PL/SQLプログラム・ユニットは、一般に、次のように分類されます。
PL/SQLサブプログラムとは、データベースに格納され、アプリケーションから名前でコールできるPL/SQLブロックのことです。サブプログラムを作成すると、データベースではそのサブプログラムを解析し、解析後の表現をデータベースに格納します。サブプログラムは、プロシージャまたはファンクションとして宣言できます。
PL/SQL無名ブロックとは、アプリケーション内に表示されるが名前が付いていない、またはデータベースに格納されていないPL/SQLブロックです。多くのアプリケーションでは、SQL文を記述できるところであればどこにでもPL/SQLブロックを記述できます。
PL/SQLのコンパイラとインタプリタはOracle SQL Developerに埋め込まれており、開発者にクライアントとサーバーの両方で一貫性のある高度な開発モデルを提供します。また、PL/SQLストアド・プロシージャは、Pro*C、JDBC、ODBCまたはOCIなどの複数のデータベース・クライアント、およびOracle ReportsとOracle Formsからコールできます。
関連項目:
パッケージなどのPL/SQLの詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
PL/SQLサブプログラムは、コール元から、入力のみ、出力のみまたは入出力の値が入るパラメータを指定できる名前付きのPL/SQLブロックです。
サブプログラムは特定の問題を解決するか、関連するタスクを実行してモジュール式のメンテナンス可能なデータベース・アプリケーションのビルディング・ブロックとして機能します。サブプログラムは、PL/SQLプロシージャまたはPL/SQLファンクションのいずれかです。プロシージャとファンクションはほとんど同じものですが、プロシージャはコール元に値を戻さないのに対して、ファンクションは必ず1つの値を戻すという違いがあります。この章では、PL/SQLプロシージャという語でプロシージャとファンクションのいずれかを指すものとします。
関連項目:
これらの言語のストアド・プロシージャの詳細は、Pro*C/C++プログラマーズ・ガイドおよびPro*COBOLプログラマーズ・ガイドを参照してください
Oracle Database PL/SQL言語リファレンス
サーバー側プログラミングにはクライアント側プログラミングよりも多くの利点があります。
次のような利点があります。
パフォーマンスの改善
メモリー割当て
ストアド・プロシージャは、Oracle Databaseの共有メモリー機能を活用しているため、複数のユーザーが実行する場合も、メモリーにロードする必要があるのはプロシージャのコピー1つのみです。コードを複数のユーザーが共有すれば、アプリケーションに必要なデータベース・メモリー要件を実質的に削減できます。
生産性の向上
ストアド・プロシージャにより、開発の生産性が向上します。共通のプロシージャを中心にしてアプリケーションを設計することにより、冗長なコーディングを回避できます。たとえば、プロシージャを記述してemployees
表内の行を操作できます。どのアプリケーションでも、これらのプロシージャをコールするためにSQL文を書きなおす必要はありません。データ管理の方法に変更があった場合も、修正する必要があるのはプロシージャのみで、プロシージャを使用するアプリケーションを修正する必要はありません。
ストアド・プロシージャは、コードを再利用するための最善の方法です。任意の言語で記述されたデータベース接続を行うどのクライアント・アプリケーションもストアド・プロシージャを起動できるため、すべての環境において最大限にコードを再利用できます。
整合性
ストアド・プロシージャにより、アプリケーションの整合性と一貫性が向上します。共通のプロシージャ群を中心としてアプリケーションを開発すれば、コーディング・エラーの発生回数が少なくなります。
たとえば、サブプログラムが正確な結果を戻すかどうかをテストし、検証後は、そのサブプログラムを必要な数のアプリケーションで再利用でき、再びテストする必要はありません。プロシージャにより参照されるデータ構造が変更された場合には、プロシージャの再コンパイルのみが必要になります。プロシージャをコールするアプリケーションの修正は、必ずしも必要ありません。
定義者権限プロシージャでのセキュリティ
ストアド・プロシージャを使用すると、データのセキュリティが向上します。定義者権限PL/SQLプロシージャは、現行のユーザーではなくその所有者の権限で実行されます。このため、定義者の権限で実行するプロシージャとファンクションを介してのみユーザーがデータにアクセスできるようにすると、ユーザーが実行するデータベース・タスクを制限できます。
たとえば、表を更新するプロシージャへのアクセス権は付与しても、その表自体へのアクセス権は付与しないこともできます。ユーザーがプロシージャを呼び出すと、そのプロシージャがプロシージャの所有者の権限で実行されます。プロシージャの実行権限しかなく、表データの問合せ、更新または削除の権限を持たないユーザーは、プロシージャを呼び出すことはできても、表のデータをそれ以外の方法では操作できません。
実行者権限プロシージャで継承される権限およびスキーマのコンテキスト
実行者権限PL/SQLプロシージャは、現行のユーザーの権限で現行のユーザーのスキーマ内で実行されます。言い換えると、実行者権限プロシージャは特定のユーザーまたはスキーマに結び付けられていません。アプリケーション開発者は、実行者権限プロシージャにより、基礎となるデータが複数のユーザー・スキーマに分割されていても、アプリケーション・ロジックを容易に一元化できます。
たとえば、hr.employees
表の更新プロシージャを実行するhr_manager
ユーザーは給与を更新できますが、同じプロシージャを実行するhr_clerk
は住所データの更新のみに操作を制限されます。
関連項目:
PL/SQLサブプログラムの概要は、Oracle Database PL/SQL言語リファレンスを参照してください
定義者および実行者の権限の詳細は、Oracle Databaseセキュリティ・ガイドを参照してください
スタンドアロンのストアド・サブプログラムは、CREATE PROCEDURE
文またはCREATE FUNCTION
文を使用してスキーマ・レベルで作成されたサブプログラムです。パッケージに定義されているサブプログラムはパッケージ・サブプログラムと呼ばれ、パッケージの一部とみなされます。
データベースは、データ・ディクショナリにスキーマ・オブジェクトとしてサブプログラムを格納します。サブプログラムには、パラメータの記述などの仕様部と本体があります。
例8-1 PL/SQLプロシージャ
この例に、スタンドアロンのPL/SQLプロシージャhire_employees
を作成する文の一部を示します。プロシージャは、employees
表に1つの行を挿入します。CREATE PROCEDURE hire_employees (p_last_name VARCHAR2, p_job_id VARCHAR2, p_manager_id NUMBER, p_hire_date DATE, p_salary NUMBER, p_commission_pct NUMBER, p_department_id NUMBER) IS BEGIN . . . INSERT INTO employees (employee_id, last_name, job_id, manager_id, hire_date, salary, commission_pct, department_id) VALUES (emp_sequence.NEXTVAL, p_last_name, p_job_id, p_manager_id, p_hire_date, p_salary, p_commission_pct, p_department_id); . . . END;
関連項目:
サブプログラムの作成方法の詳細は、Oracle Database 2日で開発者ガイドを参照してください
CREATE PROCEDURE
文の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
ユーザーは、複数の方法で対話的にサブプログラムを実行できます。
オプションは次のとおりです。
SQL*PlusまたはSQL DeveloperなどのOracleツールを使用します(「データベース開発者向けのツール」を参照)
Oracle Formsやプリコンパイラのアプリケーションなど、データベース・アプリケーションのコード内で明示的にコールします(「クライアント側のデータベース・プログラミング」を参照)
別のプロシージャやトリガーのコード内で明示的にコールします。
図8-1に、各種のデータベース・アプリケーションがhire_employees
をコールする状態を示します。
また、権限を付与されたユーザーは、Oracle Enterprise ManagerまたはSQL*Plusを使用して、次のような文でhire_employees
プロシージャを実行できます。
EXECUTE hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
この文により、employees
表にTSMITH
のための新しいレコードが挿入されます。
ストアド・プロシージャは、プロシージャの本体で参照されるオブジェクトに依存しています。データベースは、この依存性を自動的に追跡して管理します。たとえば、プロシージャに影響を及ぼす方法でhire_employees
プロシージャが参照しているemployees
表の定義を変更した場合は、プロシージャを再コンパイルして、引き続き設計どおりに機能することを確認する必要があります。通常、データベースはこのような依存性の管理を自動的に処理します。
関連項目:
PL/SQLサブプログラムの使用方法の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
EXECUTE
コマンドの詳細は、SQL*Plusユーザーズ・ガイドおよびリファレンスを参照してください
PL/SQLパッケージとは、関連するサブプログラムおよびこれらが使用するカーソルと変数をグループとしてまとめたもので、1単位として継続的に使用できるようにデータベースに格納されています。パッケージ化されたプログラムは、アプリケーションまたはユーザーから明示的にコールできます。
Oracle Databaseにはオラクル社が提供するパッケージが多数含まれており、これらのパッケージはデータベースの機能性を拡張してSQL機能へのPL/SQLアクセスを提供します。たとえば、UTL_HTTP
パッケージを使用すると、PL/SQLおよびSQLからのHTTPコールアウトでインターネット上のデータにアクセスしたり、Oracle Web Server Cartridgesをコールできます。オラクル社が提供するパッケージは、アプリケーションの作成時や、独自のストアド・プロシージャを作成する場合に使用できます。
PL/SQLパッケージは、アプリケーション開発者に多くの利点を提供します。
次のような利点があります。
カプセル化
パッケージを使用すると、ストアド・プロシージャ、変数、データ型などに名前を付けて1つの単位としてこれらをカプセル化、つまりグループ化できます。カプセル化により開発時に優れた構成を実現でき、柔軟性も向上します。パッケージ本体を実際には作成せずに、仕様部を作成し、パブリック・プロシージャを参照するようにできます。カプセル化により、権限の管理が簡単になります。パッケージに対する権限を付与されたユーザーは、そのパッケージの構成メンバーにアクセスできるようになります。
データ・セキュリティ
パッケージの定義方法により、変数、カーソルおよびプロシージャをパブリックとプライベートのどちらかに指定できます。パブリックはパッケージのユーザーが直接アクセスできることを意味します。プライベートはパッケージのユーザーには非表示になっていることを意味します。
たとえば、パッケージに10個のプロシージャが含まれているとします。この中の3つのプロシージャのみをパブリックに設定して、パッケージのユーザーが実行できるように定義できます。残りのプロシージャはプライベートなので、パッケージ内のプロシージャによってのみアクセスできます。パブリックおよびプライベートのパッケージ変数を、PUBLIC
への権限付与と混同しないでください。
優れたパフォーマンス
パッケージ内のプロシージャが初めてコールされた時点で、そのパッケージ全体が小さいチャンクに分割されてメモリーにロードされます。スタンドアロン・プロシージャは個別にロードする必要があるのに対し、このロードは1回の操作で完了します。関連するパッケージ・プロシージャがコールされても、メモリーにあるコンパイル済のコードを実行すると、ディスクI/Oは発生しません。
パッケージ本体は、仕様部に影響を与えずに置換したり再コンパイルできます。その結果、パッケージ仕様部も置き換えない場合は、パッケージの構成メンバーを参照するスキーマ・オブジェクト(常に仕様部を介してアクセス)を再コンパイルする必要はありません。パッケージを使用すると、不必要な再コンパイルが最小限に抑えられるため、全体的なデータベース・パフォーマンスへの影響は少なくなります。
パッケージは、仕様部と本体の2つの部分に分けて作成します。パッケージの仕様部ではパッケージのすべてのパブリックな構成メンバーを宣言し、パッケージの本体ではパッケージのすべての構成メンバー(パブリックとプライベート)を定義します。
次の例は、employees_management
のパッケージ仕様を作成する文の一部で、このパッケージは、従業員データベースの管理に使用される複数のサブプログラムをカプセル化します。パッケージの各部分は、異なる文を使用して作成されます。
CREATE PACKAGE employees_management AS FUNCTION hire_employees (last_name VARCHAR2, job_id VARCHAR2, manager_id NUMBER, salary NUMBER, commission_pct NUMBER, department_id NUMBER) RETURN NUMBER; PROCEDURE fire_employees(employee_id NUMBER); PROCEDURE salary_raise(employee_id NUMBER, salary_incr NUMBER); . . . no_sal EXCEPTION; END employees_management;
仕様部に、ファンクションhire_employees
、プロシージャfire_employees
およびsalary_raise
と、例外であるno_sal
が宣言されています。パッケージへのアクセス権を持つユーザーは、これらすべてのパブリック・プログラム・オブジェクトを使用できます。
CREATE PACKAGE BODY
文では、仕様部で宣言されたオブジェクトを定義します。パッケージ本体は、パッケージと同じスキーマに作成する必要があります。パッケージの作成後は、これらのうちいずれかのパブリック・プロシージャまたはファンクションをコールするか、パッケージのいずれかのパブリック例外を呼び出すアプリケーションを開発できます。
関連項目:
CREATE PACKAGE
文の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
データベース・トリガー、ストアド・サブプログラム、3GLアプリケーション・プログラムおよびOracleツールは、パッケージの内容を参照できます。
次の図に、employees_management
パッケージ内のプロシージャおよびファンクションを呼び出すデータベース・アプリケーションを示します。
データベース・アプリケーションは、必要に応じて明示的にパッケージ・プロシージャをコールします。employees_management
パッケージに対する権限を付与されたユーザーは、そこに含まれている任意のプロシージャを明示的に実行できます。たとえば、SQL*Plusでは、次の文を発行してhire_employees
パッケージ・プロシージャを実行できます。
EXECUTE employees_management.hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
関連項目:
PL/SQLパッケージの概要は、Oracle Database PL/SQL言語リファレンスを参照してください
PL/SQLパッケージのコーディングの詳細は、Oracle Database開発ガイドを参照してください
PL/SQL無名ブロックは名前が付与されていない非永続PL/SQLユニットです。
典型的な無名ブロックの用途は次のとおりです。
サブプログラムおよびパッケージ構成のコールの開始
例外処理の分離
他のPL/SQLブロック内でのコードのネストによる制御の管理
無名ブロックには、ストアド・サブプログラムのコードの再利用という利点はありません。表8-1に、2つのプログラム・ユニット・タイプの相違点の概要を示します。
表8-1 無名ブロックとサブプログラムの相違点
PL/SQLユニット | 無名ブロック | サブプログラム |
---|---|---|
名前で指定するか |
いいえ |
はい |
再利用ごとにコンパイルするか |
いいえ |
いいえ |
データベースに格納されるか |
いいえ |
はい |
他のアプリケーションから起動できるか |
いいえ |
はい |
バインド変数値を戻すことができるか |
はい |
はい |
関数値を戻すことができるか |
いいえ |
はい |
パラメータを受け取ることができるか |
いいえ |
はい |
無名ブロックは宣言部(オプション)、実行可能部分および1つ以上の例外ハンドラ(オプション)から構成されています。次のサンプルの無名ブロックでは、変数に格納する従業員の姓を選択して、その名前を出力しています。
DECLARE v_lname VARCHAR2(25); BEGIN SELECT last_name INTO v_lname FROM employees WHERE employee_id = 101; DBMS_OUTPUT.PUT_LINE('Employee last name is '||v_lname); END;
Oracle Databaseでは、PL/SQLブロックをコンパイルしてSGAの共有プールに配置しますが、現行インスタンス以外で再利用するために、ソース・コードおよびコンパイル済バージョンのブロックをデータベースに格納することはありません。トリガーとは異なり、無名ブロックはメモリーにロードされるたびにコンパイルされます。共有SQLを使用すると、共有プールに入っている無名PL/SQLブロックがその共有プールからフラッシュされるまでの間は、そのブロックを再利用および共有できます。
関連項目:
無名PL/SQLブロックの詳細は、『Oracle Database開発ガイド』を参照してください
PL/SQLブロックには、様々な異なるPL/SQL言語構造を組み込むことができます。
これらの構造には、次のものが含まれます。
変数と定数
プロシージャ、ファンクションまたはパッケージ内にこれらの構造を宣言できます。SQL文やPL/SQL文では、必要になった時点で値を受け渡すために変数や定数を使用できます。
カーソル
カーソルは、Oracle Databaseデータのレコード単位での処理を容易にするために、プロシージャ、ファンクションまたはパッケージの中で明示的に宣言できます。PL/SQLエンジンで、暗黙的にカーソルを宣言することもできます。
例外
PL/SQLでは、PL/SQLコードの処理中に発生する、例外と呼ばれる内部的なエラー条件とユーザー定義のエラー条件を明示的に処理できます。
PL/SQLでは、完全なテキストが実行時まで認識されない動的SQL文を実行できます。動的SQL文は、実行時に、プログラムに入力されたりまたはプログラムにより作成される文字列に格納されます。この技法により、汎用プロシージャを作成できます。たとえば、実行時までは名前がわからない表を操作するプロシージャを作成できます。
関連項目:
動的SQLの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください
DBMS_SQL
パッケージでの動的SQLの使用方法の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください
多数のプログラミング技法は、配列、構造体、リスト、ネストした表、セットおよびツリーなどのコレクション型を使用します。これらの技法をデータベース・アプリケーション内でサポートするために、PL/SQLにはデータ型TABLE
およびVARRAY
が用意されており、連想配列、ネストした表および可変サイズ配列を宣言できます。
PL/SQLコレクションは、すべて同じ型の要素からなる順序付けられたグループです。
各要素には、コレクション内での位置を決定する一意の添字が付いています。コレクションを作成するには、最初にコレクションの型を定義してから、その型の変数を宣言します。
コレクションの機能は、ほとんどの第3世代プログラミング言語に見られる配列と同じです。また、コレクションはパラメータとして渡すことができます。そのため、データベース表との間や、クライアント側アプリケーションとストアド・サブプログラムの間で、データの列を移動するときに使用できます。
PL/SQLレコードはC、C++またはJavaの構造型に類似した、異なる型のデータ値を格納できる複合変数です。レコードは、表内の行データまたは表内の行の特定列を保持する場合に役立ちます。
名前、給与および採用日など、従業員に関するデータがあるとします。これらの項目は、型は異なりますが論理的には関連しています。項目ごとに1フィールドを含むレコードを使用すると、データを論理単位として扱うことができます。
%ROWTYPE
属性を使用すると、表の1行やカーソルからフェッチされる1行を表すレコードを宣言できます。ユーザー定義レコードの場合は、所有しているフィールドを宣言できます。
関連項目:
PL/SQLレコードの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください
PL/SQLは解析済の実行およびシステム固有の実行の両方をサポートします。
解析済の実行では、PL/SQLソース・コードがいわゆるバイトコード表現にコンパイルされます。Oracle Databaseの一部として実装されている移植可能な仮想コンピュータによって、このバイトコードが実行されます。
システム固有の実行では、計算集中型のプログラム・ユニットで最大限のパフォーマンスが発揮されます。この場合は、PL/SQLプログラム・ユニットのソース・コードが特定のプラットフォームのオブジェクト・コードに直接コンパイルされます。このオブジェクト・コードは、Oracle Databaseにリンクされます。
PL/SQLエンジンは、PL/SQLプログラム・ユニットを定義、コンパイルおよび実行します。このエンジンは、Oracle Databaseをはじめとする多数のOracle製品に組み込まれている特別なコンポーネントです。多くのOracle製品にPL/SQLコンポーネントが含まれていますが、このトピックでは、Oracle Databaseに格納でき、Oracle DatabaseのPL/SQLエンジンを使用して処理できるプログラム・ユニットについて説明します。各Oracleツール用のドキュメントでは、それぞれのPL/SQL機能について説明します。
次の図に、Oracle Databaseに含まれているPL/SQLエンジンを示します。
プログラム・ユニットは、データベースに格納されています。アプリケションがストアド・プロシージャをコールすると、データベースは、コンパイル済のプログラム・ユニットをシステム・グローバル領域(SGA)内の共有プールにロードします(「共有プール」を参照)。PL/SQL文エグゼキュータとSQL文エグゼキュータは、連動してプロシージャ内の文を処理します。
別のPL/SQLブロック(無名ブロックまたは別のストアド・プロシージャ)からストアド・プロシージャをコールすることもできます。たとえば、Oracle Formsからストアド・プロシージャをコールできます。
Oracle Database上で実行されるPL/SQLプロシージャからは、Cプログラミング言語で作成して共有ライブラリに格納した外部プロシージャや外部ファンクションをコールできます。Cルーチンは、Oracle Databaseとは別のアドレス空間で実行されます。
関連項目:
PL/SQLアーキテクチャの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください
外部プロシージャの詳細は、『Oracle Database開発ガイド』を参照してください
オブジェクト指向プログラミング言語の選択肢として、Javaがあります。
Javaの機能は、次のとおりです。
Java仮想マシン(JVM)。プラットフォームの独立性を確保するための基礎を提供します。
自動ストレージ管理機能。ガーベージ・コレクションなどがあります。
C言語に基づく言語構文。強い型指定が必要です。
注意:
この章は、Java言語に関するある程度の知識があることを前提としています。
データベースは、複雑な問合せおよび複数のデータ・ビューをサポートする動的データ処理エンジンを備えたJavaプログラムを提供しています。クライアント要求は、即時処理されるようにデータ問合せとして組み立てられます。問合せの結果は動的に生成されます。
JavaとOracle Databaseの組合せによって、ビジネス・ニーズの変更に応じて簡単に更新できるコンポーネントベースかつネットワーク中心のアプリケーションを作成できます。また、アプリケーションおよびデータ・ストアは、デスクトップからインテリジェント・ネットワーク上およびネットワーク中心のサーバー上に移動できます。さらに重要なのは、任意のクライアント・デバイスからこれらのアプリケーションおよびデータ・ストアにアクセスできることです。
次の図は、従来の2層のクライアント/サーバー構成を示しています。この構成では、クライアントは、PL/SQLサブプログラムをコールする際と同じ方法でJavaストアド・プロシージャをコールします。
関連項目:
Oracle DatabaseでのJavaの使用方法の概要は、『Oracle Database 2日でJava開発者ガイド』を参照してください
JVMはコンパイル済のJavaコードを実行する仮想プロセッサです。
Javaソース・コードは、バイトコードと呼ばれる、プラットフォームに依存しない低レベルのマシン命令にコンパイルされます。Javaバイトコードは、JVMを介して、プラットフォームに依存する処理に解釈されます。
Oracle JVMは、Pure Javaアプリケーションを実行する標準的なJava互換環境です。JLSおよびJVMの仕様と互換性があります。
Oracle JVMでは、標準のJavaバイナリ形式とAPIがサポートされます。また、Oracle Databaseは、実行時の動的クラス・ロードなど、標準のJava言語のセマンティクスに準拠しています。
次の図に、OracleのJavaアプリケーションがJavaコア・クラス・ライブラリの最上位に配置され、さらに、Oracle JVMの最上位に配置される様子を示します。OracleのJavaサポート・システムはデータベース内に配置されるので、JVMはオペレーティング・システムと直接対話するかわりに、データベースのライブラリと対話します。
他のJava環境とは異なり、Oracle JVMはOracle Database内に埋め込まれています。Oracle JVMと典型的なクライアントJVMには、いくつかの重要な違いがあります。たとえば、標準のJava環境では、コマンドラインで次のコマンドを発行し、インタプリタを介してJavaアプリケーションを実行します(classname
は、JVMにより最初に解釈されるクラス名です)。
java classname
このコマンドによって、オペレーティング・システム上のプロセス内でアプリケーションが実行されます。ただし、コマンドライン・インタフェースを使用していない場合は、アプリケーションをデータベースにロードして、インタフェースをパブリッシュしてから、データベース・データ・ディクショナリ内のアプリケーションを実行します。
関連項目:
Oracle JVMと典型的なクライアントJVMのその他の相違の詳細は、『Oracle Database Java開発者ガイド』を参照してください
Oracle JVMはデータベースのメモリー・ヒープを共有してリレーショナル・データに直接アクセスするため、データベース・カーネルと同じ処理領域およびアドレス領域で実行されます。この設計によりメモリーの使用を最適化して、スループットを向上させます。
Oracle JVMは、Javaオブジェクトの実行時環境を提供します。Javaのデータ構造、メソッド・ディスパッチ、例外処理および言語レベル・スレッドを完全にサポートします。また、java.lang
、java.io
、java.net
、java.math
およびjava.util
など、すべてのコアJavaクラス・ライブラリもサポートしています。
次の図に、Oracle JVMの主要なコンポーネントを示します。
Oracle JVMは、データベース・スキーマに標準のJavaネームスペースを埋め込みます。この機能により、JavaプログラムはOracle Databaseに格納されたJavaオブジェクトおよび企業内のアプリケーション・サーバーにアクセスできます。
また、Oracle JVMは、データベースのスケーラブルな共有メモリー・アーキテクチャと緊密に統合されています。Javaプログラムは、ユーザーの介入なしで効率的にコール、セッションおよびオブジェクトの存続期間を使用します。結果として、セッションが継続状態であっても、Oracle JVMおよび中間層のJavaビジネス・オブジェクトのスケーラビリティを維持できます。
関連項目:
Oracle JVMの主要なコンポーネントの詳細は、Oracle Database Java開発者ガイドを参照してください
オラクル社は、エンタープライズ・アプリケーションの開発者に、Javaアプリケーションの作成、デプロイおよび管理のためのエンドツーエンドのJavaソリューションを提供します。
このソリューションは、クライアント側とサーバー側のプログラム・インタフェース、Java開発をサポートするためのツール、Oracle Databaseと統合されたJava仮想マシンで構成されています。これらの製品はいずれも、Java標準との互換性を持っています。
Javaプログラミング環境は、次の追加機能で構成されています。
PL/SQLに等価および相当するJavaストアド・プロシージャ。Javaストアド・プロシージャは、PL/SQLと緊密に統合されています。Javaストアド・プロシージャはPL/SQLパッケージから、プロシージャはJavaストアド・プロシージャからコールできます。
SQLデータにアクセスするためのJDBCおよびSQLJプログラミング・インタフェース。
クラスの開発、ロードおよび管理を支援するツールおよびスクリプト。
Javaストアド・プロシージャは、SQLにパブリッシュされデータベースに格納されるJavaメソッドです。
PL/SQLサブプログラムと同様に、Javaプロシージャには、SQL*Plusなどの製品で直接起動する方法と、トリガーを使用して間接的に起動する方法があります。また、OCI、プリコンパイラまたはJDBCなど、すべてのOracle Netクライアントからアクセスできます。
Javaメソッドをパブリッシュするには、Javaメソッド名、パラメータの型およびSQLの対応部分への戻り型をマップするコール仕様を記述します。クライアント・アプリケーションからコールされると、Javaストアド・プロシージャは引数を受け取り、Javaクラスを参照してJavaの結果値を戻すことができます。
アプリケーションは、コール仕様の名前を参照することにより、Javaメソッドをコールします。実行時のシステムは、Oracleデータ・ディクショナリ内のコール仕様の定義を検索し、該当のJavaメソッドを実行します。
また、Javaを使用して、PL/SQLに依存しない強力なプログラムを開発することもできます。Oracle Databaseには、Javaプログラミング言語とJVMの完全準拠の実装が用意されています。
関連項目:
Javaでストアド・プロシージャを記述する方法、PL/SQLからアクセスする方法およびJavaからPL/SQL機能にアクセスする方法は、Oracle Database Java開発者ガイドを参照してください
既存のPL/SQLプログラムをJavaから呼び出したり、JavaプログラムをPL/SQLから起動できます。このソリューションでは、PL/SQLおよびJavaコードを保護して活用します。
Oracle DatabaseはJava、JDBCおよびSQLJからSQLデータにアクセスするために、異なる2つのアプローチを提供しています。クライアントおよびサーバー上で両方のアプローチを使用できます。このため、コードを変更することなく、クライアントおよびサーバー上にアプリケーションをデプロイできます。
JDBCは、ユーザーがデータベースに接続してSQL文を実行し、データベースに問合せできるようにするデータベース・アクセス・プロトコルです。
コアJavaクラス・ライブラリには、JDBC APIのjava.sql
が1つのみ用意されています。ただし、JDBCは、ベンダーが特定のデータベースを必要に応じて特化するためのドライバを提供できるように設計されています。Oracleには、次の表に示す個々のJDBCドライバが用意されています。
表8-2 JDBCドライバ
ドライバ | 説明 |
---|---|
JDBC Thinドライバ |
JDBC Thinドライバを使用すると、Oracle SQLのデータにアクセスするPure Javaアプリケーションおよびアプレットを作成できます。JDBC Thinドライバは、他のJavaアプレットと同様にWebページから動的にダウンロードできるため、Webベースのアプリケーションとアプレットに特に適しています。 |
JDBC OCIドライバ |
JDBC OCIドライバは、クライアントまたは中間層にあるOracle固有のネイティブ・コード(つまり非Javaコード)およびライブラリにアクセスし、JDBC Thinドライバに比べてパフォーマンスが向上しますが、サイズが極端に大きくなることと、クライアント側でのインストールというコストの問題があります。 |
サーバー側JDBC内部ドライバ |
Oracle Databaseは、Javaコードがサーバー上で実行される場合に、サーバー側内部ドライバを使用します。これにより、サーバーのOracle JVM内で実行中のJavaアプリケーションは、JDBCを使用してローカルに定義されたデータ(つまり、同じシステムの同じプロセスにあるデータ)にアクセスできます。また、基礎となるOracle RDBMSライブラリを直接使用できるため、パフォーマンスが向上し、JavaコードとSQLデータの間にネットワーク接続が介入することによるオーバーヘッドは発生しません。Oracle Databaseでは、サーバー上で同じJava-SQLインタフェースがサポートされるため、デプロイ時にコードの再処理を必要としません。 |
関連項目:
Oracle Database 2日でJava開発者ガイドおよびOracle Database JDBC開発者ガイド
SQLJは、JavaプログラムにSQL文を埋め込むためのANSI標準です。
Oracle Database環境内では、ストアド・プロシージャ、トリガーおよびメソッドでSQLJを使用できます。また、SQLJプログラムをJDBCと組み合せることもできます。
SQLJは、Javaからデータベースにアクセスするクライアント側および中間層のアプリケーションを開発するための、単純ですが強力な方法を提供します。開発者はSQLJを使用してプログラムを記述し、その後SQLJトランスレータを使用して埋め込まれたSQLをJDBCベースのPure Javaコードに変換します。実行時に、プログラムは標準のJDBCドライバを使用して、複数のベンダーのデータベースと通信できます。
次の例は、簡単な実行可能SQLJ文を示しています。
String name; #sql { SELECT first_name INTO :name FROM employees WHERE employee_id=112 }; System.out.println("Name is " + name + ", employee number = " + employee_id);
Oracle Databaseは完全なJava環境を提供しているため、データベースで実行されるSQLJプログラムをクライアント上ではコンパイルできません。かわりに、サーバー上でそれらを直接コンパイルできます。
関連項目:
『Oracle Database SQLJ開発者ガイド』
データベースのトリガーはコンパイル済のストアド・プログラム・ユニットであり、PL/SQLまたはJavaのいずれかで記述されます。Oracle Databaseは、特定の状況で自動的にトリガーの呼出し(起動)を行います。
トリガーは、次のいずれかの操作が発生するたびに起動します。
任意のユーザーによって発行された、特定の表またはビューに対するDML文
DML文は、スキーマ・オブジェクト内のデータを変更します。たとえば、行の挿入および削除はDMLの処理です。
特定のユーザーまたは任意のユーザーのいずれかが発行したDDL文
DDL文は、スキーマ・オブジェクトを定義します。たとえば、表の作成および列の追加はDDLの処理です。
データベース・イベント
ユーザーのログインまたはログオフ、エラーおよびデータベースの起動または停止は、トリガーを起動できるイベントです。
トリガーはサブプログラムに類似したスキーマ・オブジェクトですが、起動方法が異なります。サブプログラムはユーザー、アプリケーションまたはトリガーによって明示的に実行されます。トリガーは、トリガー・イベントが発生したときにデータベースによって暗黙的に起動されます。
関連項目:
DMLおよびDDLの詳細は、「SQL文の概要」を参照してください
トリガーを正しく使用すると、ユーザーはデータベースをより効率的に使用するさらに堅牢なアプリケーションを構築してデプロイできます。
トリガーは、次のような目的で使用できます。
導出列の値の自動的な生成
不正なトランザクションの防止
監査およびイベント・ロギングの提供
表アクセスについての情報の記録
トリガーを使用して、すべてのクライアント・アプリケーションに共通の低レベルでのビジネス・ルールを強制実行できます。たとえば、複数のアプリケーションからemployees
表にアクセスできます。この表でのトリガーで挿入されるデータの形式が保証される場合は、クライアントごとにこのビジネス・ロジックを再作成する必要はありません。アプリケーションはトリガーを回避できないため、トリガー内のビジネス・ロジックが自動的に使用されます。
トリガーと整合性制約を併用すると、任意の整合性規則を定義して規定できます。ただし、整合性制約を使用して定義できない複雑なビジネス・ルールを強制する場合にのみ、トリガーを使用することをお薦めします。
トリガーを使用しすぎると相互依存性が複雑になるため、大規模アプリケーションのメンテナンスが困難になります。たとえば、トリガーが起動されると、そのトリガー・アクションに含まれるSQL文によって他のトリガーが起動されてトリガーの連鎖状態になり、意図しない影響が起きる可能性があります。
関連項目:
『Oracle Database 2日で開発者ガイド』
アプリケーションのトリガーを計画する場合のガイドラインおよび制限の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
トリガーは、起動方法と実行するアクションのタイプに応じて分類できます。
Oracle Databaseは次のタイプのトリガーをサポートしています。
行トリガー
行トリガーは、表がトリガーを実行する文の処理の影響を受けるたびに実行されます。たとえば、文が複数の行を更新する場合、UPDATE
が処理する行ごとに1つずつ行トリガーが起動されます。トリガーを実行する文の影響を受ける行がなければ、行トリガーは実行されません。トリガー・アクションのコードが、トリガーを実行する文によって供給されるデータまたは影響を受ける行数に依存する場合には、行トリガーが便利です。
文トリガー
文トリガーは、トリガーを実行する文の影響を受ける行数とは関係なく、トリガーを実行する文の実行ごとに1回起動されます。たとえば、文が表から100行を削除すると、文レベルのDELETE
トリガーが1回のみ起動されます。トリガー・アクションのコードが、トリガーを実行する文によって供給されるデータや、影響を受ける行に依存しない場合には、文トリガーが便利です。
INSTEAD OF
トリガー
INSTEAD OFトリガーは、トリガーを実行する文のかわりに、Oracle Databaseによって起動されます。これらのトリガーは、DML文を介して直接変更できないビューを透過的に変更する場合に便利です。
イベント・トリガー
トリガーを使用すると、データベース・イベントに関する情報を、サブスクライバに対して発行できます。イベント・トリガーは、次のカテゴリに分類されます。
システム・イベント・トリガー: データベース・インスタンスの起動および停止またはエラー・メッセージなどのイベントによって起動できます。
ユーザー・イベント・トリガー: ユーザーのログオンおよびログオフに関連したイベント、DDL文およびDML文によって起動されます。
関連項目:
『Oracle Database 2日で開発者ガイド』
Oracle Database PL/SQL言語リファレンス
トリガーのタイミング(トリガー・アクションをトリガー実行文の前と後のどちらで実行するか)を定義できます。
単純なトリガーは表の単一のトリガーであり、次のいずれか1つのタイミング・ポイントに対してのみアクションを指定できます。
起動文の前
起動文によって影響を受ける各行の前
起動文によって影響を受ける各行の後
起動文の後
文および行のトリガーの場合、BEFORE
トリガーによってセキュリティを高め、データベースに変更を加える前にビジネス・ルールを有効にできます。アクションのロギングには、AFTER
トリガーが理想的です。
複合トリガーは、複数のタイミング・ポイントで起動できます。複合トリガーは、様々なタイミング・ポイントに対して実装するアクションで共通データを共有するためのアプローチをプログラム化する際に役立ちます。
関連項目:
複合トリガーの詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
CREATE TRIGGER
文はデータベース・トリガーを作成または置き換えます。
PL/SQLトリガーの一般的な構文形式は次のとおりです。
CREATE TRIGGER trigger_name triggering_statement [trigger_restriction] BEGIN triggered_action; END;
PL/SQLトリガーの基本的なコンポーネントは次のとおりです。
トリガー名
名前は、同じスキーマ内の他のトリガーの中で一意であることが必要です。たとえば、part_reorder_trigger
などの名前にできます。
トリガー・イベントまたはトリガーを実行する文
トリガー・イベントまたはトリガーを実行する文とは、トリガーを起動させるSQL文、データベース・イベントまたはユーザー・イベントのことです。たとえば、ユーザーによる表の更新などです。
トリガー制限
トリガー制限にはブール式を指定し、トリガーが起動されるには、そのブール式がtrue
になる必要があります。たとえば、引当可能部品の数量が現行の再発注数量より少なくなるまで、トリガーは起動されません。
トリガー・アクション
トリガー・アクションは、トリガーを実行する文が発行され、トリガーの制限がtrueに評価された場合に実行されるSQL文およびコードを含むプロシージャです。たとえば、ユーザーが保留中のorders表に行を挿入します。
関連項目:
トリガーの作成方法の詳細は、Oracle Database 2日で開発者ガイドおよびOracle Database PL/SQL言語リファレンスを参照してください
CREATE TRIGGER
文の詳細は、Oracle Database SQL言語リファレンスを参照してください
この例では、明細項目表でINSERT
文、UPDATE
文またはDELETE
文が実行されると起動されるトリガーを作成します。
次の文を使用してorders
表およびlineitems
表を作成するとします。orders
表は一意のオーダーごとに行を保持するのに対して、lineitems
表は1つのオーダー内の項目ごとに行を保持します。
CREATE TABLE orders ( order_id NUMBER PRIMARY KEY, /* other attributes */ line_items_count NUMBER DEFAULT 0 ); CREATE TABLE lineitems ( order_id REFERENCES orders, seq_no NUMBER, /* other attributes */ CONSTRAINT lineitems PRIMARY KEY(order_id,seq_no) );
次の文で、orders
表内のオーダーの項目数を自動的に更新するサンプル・トリガーを作成します。
CREATE OR REPLACE TRIGGER lineitems_trigger AFTER INSERT OR UPDATE OR DELETE ON lineitems FOR EACH ROW BEGIN IF (INSERTING OR UPDATING) THEN UPDATE orders SET line_items_count = NVL(line_items_count,0)+1 WHERE order_id = :new.order_id; END IF; IF (DELETING OR UPDATING) THEN UPDATE orders SET line_items_count = NVL(line_items_count,0)-1 WHERE order_id = :old.order_id; END IF; END; /
lineitems_trigger
でトリガーを実行する文は、lineitems
表に対するINSERT
、UPDATE
またはDELETE
です。トリガー制限はありません。変更される行ごとに、トリガーが起動されます。トリガーは、トリガーを実行する文によって影響を受ける現在の行の、新旧の列値にアクセスできます。表の変更対象の列ごとに、古い値(:old
)および新しい値(:new
)の2つの相関名があります。セッションで、あるオーダーについてlineitems
の行を更新または挿入すると、このアクションの後、トリガーによってこのオーダーの項目数が計算され、orders
表の数値が更新されます。
このシナリオでは、顧客は2つのオーダーを開始し、オーダーの明細項目を追加および削除します。
シナリオは、「例: CREATE TRIGGER文」で作成されたトリガーに基づいています。
表8-3 行レベル・トリガーの使用例
SQL文 | トリガーされるSQL文 | 説明 |
---|---|---|
SQL> INSERT INTO orders (order_id) VALUES (78); 1 row created. |
顧客がID78のオーダーを作成します。この時点で、顧客のオーダーに項目はありません。
|
|
SQL> INSERT INTO orders (order_id) VALUES (92); 1 row created. |
顧客がID92の別のオーダーを作成します。この時点で、顧客のオーダーに項目はありません。
|
|
SQL> INSERT INTO lineitems (order_id, seq_no) VALUES (78,1); 1 row created. |
UPDATE orders SET line_items_count = NVL(NULL,0)+1 WHERE order_id = 78; |
顧客がオーダー78に項目を追加します。
|
SQL> INSERT INTO lineitems (order_id, seq_no) VALUES (78,2); 1 row created. |
UPDATE orders SET line_items_count = NVL(1,0)+1 WHERE order_id = 78; |
顧客がオーダー78にさらに項目を追加します。
|
SQL> SELECT * FROM orders; ORDER_ID LINE_ITEMS_COUNT --------- ---------------- 78 2 92 0 |
顧客が2つのオーダーのステータスを問い合せます。オーダー78には2つの項目があります。オーダー92には項目がありません。 |
|
SQL> SELECT * FROM lineitems; ORDER_ID SEQ_NO ---------- ---------- 78 1 78 2 |
顧客は明細項目のステータスを問い合せます。各項目は注文IDと順序番号によって一意に識別されます。 |
|
SQL> UPDATE lineitems SET order_id = 92; 2 rows updated. |
UPDATE orders SET line_items_count = NVL(NULL,0)+1 WHERE order_id = 92; UPDATE orders SET line_items_count = NVL(2,0)-1 WHERE order_id = 78; UPDATE orders SET line_items_count = NVL(1,0)+1 WHERE order_id = 92; UPDATE orders SET line_items_count = NVL(1,0)-1 WHERE order_id = 78; |
顧客がオーダー78の明細項目をオーダー92に移動します。
トリガーが起動されるたびに、トリガーの両方の |
SQL> SELECT * FROM orders; ORDER_ID LINE_ITEMS_COUNT --------- ---------------- 78 0 92 2 |
顧客が2つのオーダーのステータスを問い合せます。実際の結果としては、オーダー92の明細項目数が0から2に増加し、オーダー78の数が2から0に減少しています。 |
|
SQL> SELECT * FROM lineitems; ORDER_ID SEQ_NO ---------- ---------- 92 1 92 2 |
顧客は明細項目のステータスを問い合せます。各項目は注文IDと順序番号によって一意に識別されます。 |
|
SQL> DELETE FROM lineitems; 2 rows deleted. |
UPDATE orders SET line_items_count = NVL(2,0)-1 WHERE order_id = 92; UPDATE orders SET line_items_count = NVL(1,0)-1 WHERE order_id = 92; |
顧客はすべてのオーダーからすべての明細項目を削除します。
|
SQL> SELECT * FROM orders; ORDER_ID LINE_ITEMS_COUNT --------- ---------------- 78 0 92 0 SQL> SELECT * FROM lineitems; no rows selected |
顧客が2つのオーダーのステータスを問い合せます。どちらのオーダーにも明細項目がありません。 また、顧客は明細項目のステータスも問い合せます。項目は存在しません。 |
Oracle Databaseは、サブプログラムの実行と同じ手順を使用してトリガーを内部的に実行します。
両者の唯一の違いは、ユーザー・アカウントがトリガー文を実行する権限を持っていれば、トリガーを起動する権限が付与されることです。この例外を除いて、データベースはストアド・サブプログラムと同じ方法でトリガーを検証して実行します。
関連項目:
トリガー実行の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください
Oracle Databaseでは、PL/SQLストアド・プロシージャと同じように、コンパイル済の形式でデータベース・スキーマにPL/SQLトリガーを格納します。
CREATE TRIGGER
文がコミットすると、コンパイルされたPL/SQLコードがデータベースに格納されます。共有プールからPL/SQLトリガーのソース・コードが削除されます。
次の図に示すデータベース・アプリケーションには、PL/SQLトリガーを暗黙のうちに起動するSQL文が含まれています。トリガーは、それに対応付けられている表とは別々に格納されています。
Javaトリガーは、PL/SQLトリガーと同じ方法で格納されます。ただし、Javaトリガーでは、CALL
文を使用して、個別にコンパイルされたJavaコードを参照します。このため、Javaトリガーを作成する場合は、JavaコードおよびこのJavaコードを参照するトリガーを作成することが必要となります。
関連項目:
トリガーのコンパイルおよび格納の詳細は、Oracle Database PL/SQL言語リファレンスを参照してください