ヘッダーをスキップ
Oracle® Call Interfaceプログラマーズ・ガイド
11g リリース2 (11.2)
E50264-03
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

14 OCIのオブジェクトに関する高度なトピック

この章では、オブジェクトをOracle Databaseで操作するためのOCIの機能を紹介します。また、OCIのオブジェクト・ナビゲーショナル関数コール、型進化およびXMLのサポートについても説明します。

この章は、次の項目で構成されています。

オブジェクト・キャッシュおよびメモリー管理

オブジェクト・キャッシュは、オブジェクトの参照とメモリー管理をサポートするクライアント側のメモリー・バッファです。これはOCIアプリケーションでフェッチしたオブジェクト・インスタンスを格納し、追跡するためのものです。オブジェクト・キャッシュには、メモリー管理が用意されています。

アプリケーションでSQLのSELECT文またはOCIのPINオペレーションによってオブジェクトをフェッチすると、オブジェクトのコピーがオブジェクト・キャッシュに格納されます。SELECT文で直接フェッチされたオブジェクトは、値によってフェッチされる、確保できない参照不可能なオブジェクトです。確保できるのは参照可能オブジェクトのみです。

オブジェクトを確保するとき、適切なバージョンのオブジェクトがキャッシュ内に存在していれば、サーバーからオブジェクトをフェッチする必要はありません。

OCIを使用してREFを参照解除し、オブジェクトを取り出す各クライアント・プログラムでは、オブジェクト・キャッシュが使用されます。クライアント側のオブジェクト・キャッシュは、オブジェクト・モードで初期化されたすべてのOCI環境ハンドルで割り当てられます。1つのプロセスの複数のスレッドで、同一のOCI環境ハンドルを共有することによって同一のクライアント側キャッシュを共有できます。

オブジェクト・キャッシュ内には接続ごとに、各参照可能オブジェクトのコピーがそれぞれ1つあります。オブジェクト・キャッシュは、接続によって論理的にパーティション化されます。

1つのREFを複数回参照解除するか、同じ接続における等価な複数のREFを参照解除した場合は、オブジェクトの同一コピーが戻されます。

キャッシュ内のオブジェクトのコピーを変更する場合は、変更内容を他のプロセスに表示する前にサーバーにフラッシュする必要があります。不要になったオブジェクトは確保解除するか、または解放できます。このオブジェクトをキャッシュからスワップすることにより、占有しているメモリー領域を解放できます。

キャッシュにロードされたデータベース・オブジェクトは、C言語構造体に透過的にマップされます。オブジェクト・キャッシュでは、キャッシュ内のすべてのオブジェクト・コピーと、それぞれに対応するデータベース内のオブジェクトとの間の関連付けが、メンテナンスされます。トランザクションをコミットすると、キャッシュ内のオブジェクト・コピーに対して行った変更がデータベースに自動的に伝播されます。

オブジェクト・キャッシュではオブジェクト・コピーの内容は管理されず、オブジェクト・コピーが自動的にリフレッシュされることもありません。アプリケーションでは、オブジェクト・コピーの内容の正確さと一貫性を確保する必要があります。たとえば、アプリケーションが挿入、更新または削除を行うためにオブジェクト・コピーにマークを付け、トランザクションを終了した場合、キャッシュはオブジェクト・コピーのマークを解除するだけであり、コピーを消去したり無効化したりしません。アプリケーションは、recentまたはlatestのオブジェクト・コピーを確保するか、または次のトランザクションでオブジェクト・コピーをリフレッシュする必要があります。アプリケーションがいずれかのオブジェクト・コピーを確保した場合、以前終了したトランザクションから変更内容がコミットされていない同じオブジェクト・コピーを取得することがあります。

オブジェクト・キャッシュは、modeOCI_OBJECTOCIEnvCreate()によってOCI環境が初期化されると作成されます。

オブジェクト・キャッシュでは、REFをオブジェクトにマッピングするための高速参照表がメンテナンスされています。アプリケーションがREFを参照解除するときに、対応するオブジェクトがオブジェクト・キャッシュにキャッシュされていない場合、オブジェクト・キャッシュは、サーバーに対して、オブジェクトをデータベースからフェッチしてオブジェクト・キャッシュにロードする要求を自動的に送信します。

同一のREFに対するその後の参照解除は、ローカル・キャッシュ・アクセスになり、ネットワークのラウンドトリップが発生しないため、より高速になります。キャッシュ内のオブジェクトにアクセス中であることをオブジェクト・キャッシュに通知するために、アプリケーションはオブジェクトを確保し、オブジェクトの処理が終了した時点で確保解除します。オブジェクト・キャッシュでは、キャッシュ内の各オブジェクトに対する確保カウントが保持されますが、このカウントは確保コールにより増加し、確保解除コールにより減少します。確保カウントが0 (ゼロ)になると、アプリケーションがそのオブジェクトを必要としなくなります。

オブジェクト・キャッシュでは、最低使用頻度(LRU)アルゴリズムを使用して、キャッシュのサイズが管理されます。LRUアルゴリズムは、キャッシュが最大サイズに達すると、候補オブジェクトを解放します。候補オブジェクトとは、確保カウントが0 (ゼロ)のオブジェクトのことです。

同じサーバーに対して稼働中の各アプリケーション・プロセスには、図14-1で示すような専用のオブジェクト・キャッシュがあります。

図14-1 オブジェクト・キャッシュ

図14-1の説明は次にあります
「図14-1 オブジェクト・キャッシュ」の説明

オブジェクト・キャッシュは、メモリーに現在あるオブジェクトの追跡、そのオブジェクトへの参照のメンテナンス、自動オブジェクト・スワッピングの管理、オブジェクトのメタ属性の追跡を行います。

キャッシュの一貫性

オブジェクト・キャッシュ内のオブジェクト・コピーと、データベース内で対応するオブジェクトとの間における値の一貫性は、自動的にはメンテナンスされません。つまり、アプリケーションでオブジェクト・コピーを変更すると、その変更内容はデータベース内の対応するオブジェクトに自動的に適用されず、その逆も同様です。オブジェクト・キャッシュでは、変更されたオブジェクト・コピーをデータベースにフラッシュする操作や、古いオブジェクト・コピーをデータベースの最新値にリフレッシュする操作が可能であり、プログラムである程度の一貫性をメンテナンスできます。


注意:

Oracle Databaseは、サーバーのバッファ・キャッシュまたはデータベースとの自動キャッシュ一貫性をサポートしていません。自動キャッシュ一貫性とは、対応するオブジェクトがサーバーのバッファ・キャッシュで変更されると、ローカル・オブジェクト・コピーがオブジェクト・キャッシュによってリフレッシュされるメカニズムを指します。このメカニズムは、オブジェクト・キャッシュが、サーバー内の対応するオブジェクトに直接アクセスする前に、ローカル・オブジェクト・コピーに行われた変更をバッファ・キャッシュにフラッシュしたとき実行されます。直接的なアクセスには、SQL、トリガーまたはストアド・プロシージャを使用した、サーバーのオブジェクトの読取りや変更が含まれます。

オブジェクト・キャッシュ・パラメータ

オブジェクト・キャッシュには、環境ハンドルの属性である、2つの重要なパラメータが関連付けられています。

  • OCI_ATTR_CACHE_MAX_SIZE – キャッシュの最大サイズ

  • OCI_ATTR_CACHE_OPT_SIZE – キャッシュの最適サイズ

これらのパラメータは、キャッシュのメモリー使用量レベルを示し、削除してもよいオブジェクトをいつ自動的にキャッシュから削除してメモリーを解放するかを判断するのに役立ちます。

現在キャッシュにあるオブジェクトのメモリー使用量が最大キャッシュ・サイズに達するかそれを超えると、キャッシュでは、確保カウントが0 (ゼロ)の、マークされていないオブジェクトの自動的な解放(またはエージ・アウト)が始まります。キャッシュのメモリー使用量が最適サイズに達するか、解放対象オブジェクトがなくなるまで、オブジェクトの解放が続きます。キャッシュが指定した最大キャッシュ・サイズを超えることがあります。

OCI_ATTR_CACHE_MAX_SIZEは、OCI_ATTR_CACHE_OPT_SIZEのパーセントで指定します。オブジェクト・キャッシュの最大サイズ(バイト単位)は、次のアルゴリズムを使用して、OCI_ATTR_CACHE_OPT_SIZEOCI_ATTR_CACHE_MAX_SIZEのパーセントで増分して計算します。

maximum_cache_size = optimal_size + optimal_size * max_size_percentage / 100

次に、環境ハンドル属性でアルゴリズムを表します。

maximum_cache_size = OCI_ATTR_CACHE_OPT_SIZE + OCI_ATTR_CACHE_OPT_SIZE * 
                                            OCI_ATTR_CACHE_MAX_SIZE / 100

OCI_ATTR_CACHE_MAX_SIZEの値は、OCI_ATTR_CACHE_OPT_SIZEの10% (デフォルト)に設定できます。OCI_ATTR_CACHE_OPT_SIZEのデフォルト値は8MBです。

環境ハンドルのキャッシュ・サイズ属性の設定にはOCIAttrSet()コールを、取出しにはOCIAttrGet()関数を使用します。


関連項目:

詳細は、「環境ハンドル属性」を参照してください。

オブジェクト・キャッシュ操作

この項では、オブジェクト・キャッシュで使用されるオブジェクト・コピーを操作する重要な関数について説明します。


関連項目:

すべてのOCIのナビゲーショナル関数、キャッシュ関数およびオブジェクトの管理関数のリストは、「OCIナビゲーショナル関数」を参照してください。

確保と確保解除

オブジェクト・コピーの確保によって、アプリケーションは、そのコピーへのREFを参照解除して、キャッシュ内のオブジェクト・コピーにアクセスできるようになります。

オブジェクトを確保解除すると、オブジェクトが現在使用中でないことがキャッシュに対して示されます。不要になったオブジェクトは確保解除してキャッシュからの暗黙的な解放の対象にし、メモリーを解放してください。

解放

オブジェクト・コピーを解放すると、オブジェクト・コピーはキャッシュから削除され、使用されていたメモリーが解放されます。

マークとマーク解除

オブジェクトをマークすることで、キャッシュ内のオブジェクト・コピーが更新されており、オブジェクト・コピーをフラッシュするときにサーバー内の対応するオブジェクトを更新する必要があることが、キャッシュに通知されます。

オブジェクトをマーク解除すると、オブジェクトが更新されたという指示が削除されます。

フラッシュ

オブジェクトをフラッシュすると、キャッシュ内のマークされたオブジェクト・コピーに対して行ったローカルな変更が、サーバー内の対応するオブジェクトに書き込まれます。それによって、オブジェクト・キャッシュ内のコピーのマークが解除されます。

リフレッシュ

キャッシュ内のオブジェクト・コピーをリフレッシュすると、そのコピーは、サーバー内の対応するオブジェクトの最新値に置き換わります。

トップレベルのオブジェクト・メモリーへのポインタは、リフレッシュ後も有効です。2次レベル・メモリーへのポインタ(文字列テキスト・ポインタ、コレクションなど)は、リフレッシュ後に無効になる場合があります。

たとえば、オブジェクトの型がpersonで、salary (NUMBER)name (VARCHAR2(20))の2つの属性を持っているとします。この型は、次のとおりです。

struct Person {
OCINumber salary;
OCIString *name;
}

クライアントがPersonインスタンスへのポインタscott_pを持っており、そのインスタンスに対してOCIObjectRefresh()をコールする場合、ポインタscott_pはリフレッシュ後も同じままですが、scott_p->nameなどの第2レベルのメモリーへのポインタは異なることがあります。

オブジェクト・コピーのロードと削除

この項では、確保、確保解除および解放の各関数を説明します。

オブジェクト・コピーの確保

オブジェクト・キャッシュ内のREFをアプリケーションで参照解除する必要がある場合は、OCIObjectPin()をコールします。このコールによってREFが参照解除され、キャッシュ内のオブジェクト・コピーが確保されます。オブジェクト・コピーは、確保されているかぎり、アプリケーションからアクセス可能であることが保証されます。OCIObjectPin()で、PINオプションであるanyrecentまたはlatestを受け付けます。PINオプションのデータ型はOCIPinOptです。

  • any (OCI_PIN_ANY)オプションが指定される場合で、キャッシュ内にオブジェクト・コピーがある場合は、それをオブジェクト・キャッシュでただちに戻します。キャッシュ内にオブジェクト・コピーがない場合、オブジェクト・キャッシュでは最新のオブジェクト・コピーをデータベースからロードして、そのオブジェクト・コピーが戻されます。anyオプションは、製品、営業担当者、ベンダー、販売領域、部品、事務所などの、読取り専用、情報、事実またはメタのオブジェクトに適しています。これらのオブジェクトは、通常は頻繁に変更されることはなく、変更されてもその変更内容はアプリケーションに影響しません。

    オブジェクト・キャッシュでは、指定された接続のキャッシュの論理パーティション内にあるオブジェクト・コピーのみが検索される点に注意してください。パーティション内にコピーがない場合、オブジェクトの最新コピーがサーバーからロードされます。

  • latest (OCI_PIN_LATEST)オプションを指定すると、オブジェクト・キャッシュは、最新のオブジェクト・コピーをデータベースからキャッシュにロードします。また、オブジェクト・コピーがキャッシュ内でロックされないかぎり、そのコピーを戻します。この場合、マークを付けられたオブジェクト・コピーが即座に戻されます。オブジェクトがキャッシュ内にあり、ロックされていない場合、最新のオブジェクト・コピーがロードされ、既存のオブジェクト・コピーを上書きします。latestオプションは、発注書、不具合、明細項目、銀行口座、株価情報などの操作オブジェクトに適しています。通常、これらのオブジェクトは頻繁に変更されるため、プログラムが、これらのオブジェクトが最新の状態のときにアクセスすることが重要になります。

  • recent (OCI_PIN_RECENT)オプションが指定される場合、2つの可能性が考えられます。

    • 同じトランザクションにおいて、latestまたはrecentオプションを使用して、オブジェクト・コピーが以前に確保されている場合は、recentオプションはanyオプションと同等になります。

    • 前述の条件が当てはまらない場合は、recentオプションはlatestオプションと同等になります。

プログラムでオブジェクトが確保される場合、プログラムではsessionまたはtransactionという2つの可能な値の内の1つが確保継続時間に指定されます。継続時間のデータ型はOCIDurationです。

  • 確保継続時間がsession (OCI_DURATION_SESSION)の場合、セッションを終了するまで(つまり接続の終了まで)、またはプログラムで(OCIObjectUnpin()をコールして)明示的に確保解除されるまで、オブジェクト・コピーは確保されたままとなります。

  • 確保継続時間がtransaction (OCI_DURATION_TRANS)の場合、トランザクションの終了まで、または明示的に確保解除されるまで、オブジェクト・コピーは確保されたままとなります。

オブジェクト・コピーをデータベースからキャッシュにロードするとき、実際にはキャッシュで次の文が実行されます。

SELECT VALUE(t) FROM t WHERE REF(t) = :r

この文では、tはオブジェクトが格納されているオブジェクト表であり、rREFです。フェッチされた値はキャッシュ内のオブジェクト・コピーの値になります。

オブジェクト・キャッシュでは、個々のSELECT文が効率的に実行され、各オブジェクト・コピーがキャッシュにロードされるため、コミット読取りトランザクションでは、オブジェクト・コピー相互の読取り一貫性は保証されません。

シリアライズ可能トランザクションでは、recentまたはlatestで確保されたオブジェクト・コピーは相互の読取り一貫性があります。これは、これらのオブジェクト・コピーをロードするSELECT文は、同じデータベース・スナップショットに基づいて実行されるためです。

コミット読取りトランザクションとシリアライズ・トランザクションは、データベースがサポート可能な異なる分離レベルを示します。これ以外にも、非コミット読取りや反復可能読取りなど様々な分離レベルがあります。各分離レベルでは、同時トランザクション間でのある程度の干渉は許容されます。通常、分離レベルでより多くの干渉が許容される場合、同時トランザクションの同時実行性が向上します。コミット読取りトランザクションでは、問合せが複数回実行された場合、コミットされた他のトランザクションによる変更が表示されるため、このタイプのランザクションでは一貫性のないデータ・セットが生成されることがあります。シリアライズ・トランザクションの場合は、このようなことはありません。

オブジェクト・キャッシュのモデルは、Oracle Databaseトランザクション・モデルに対して直交状態であるか、または独立しています。オブジェクト・キャッシュの動作は、トランザクション・モデルによって変わることはありません。ただし、同じプログラムを異なる複数のトランザクション・モデル(コミット読取りとシリアライズ可能など)のもとで実行した場合、オブジェクト・キャッシュを介してサーバーから取り出したオブジェクトは、異なることがあります。


注意:

OCIObjectArrayPin()の場合、オブジェクトは常にデータベースから取り出されるため、PINオプションは無効です。REFがキャッシュ内のオブジェクトに対するものである場合、OCIObjectArrayPin()は次のエラーで失敗します。
ORA-22881: dangling REF

オブジェクト・コピーの確保解除

プログラムで使用しないオブジェクト・コピーは、確保解除できます。その後、解放できるようになります。キャッシュのメモリーが残り少なくなった場合は、オブジェクト・コピーを完全に確保解除すると同時にマーク解除し、キャッシュ内のそのコピーを暗黙的解放の対象にする必要があります。オブジェクト・コピーを完全に確保解除するには、n回確保した場合はn回確保解除する必要があります。

確保解除済でマーク未解除のオブジェクト・コピーは、フラッシュするか、ユーザーが明示的にマーク解除しないと暗黙的解放の対象になりません。ただし、オブジェクト・キャッシュのメモリーが残り少なくなると、オブジェクト・キャッシュのオブジェクト・コピーは暗黙的に解放されるので、確保解除したオブジェクト・コピーを必ずしも解放する必要はありません。暗黙的に解放されていないオブジェクト・コピーをプログラムで(anyまたはrecentオプションを指定して)再度確保した場合、同一のオブジェクト・コピーを入手することになります。

アプリケーションでオブジェクト・コピーを確保解除するには、OCIObjectUnpin()またはOCIObjectPinCountReset()をコールします。さらに、プログラムでは、特定の接続に対してキャッシュ内のすべてのオブジェクト・コピーを完全に確保解除するために、OCICacheUnpin()をコールできます。

オブジェクト・コピーの解放

オブジェクト・コピーの解放とは、オブジェクト・キャッシュからオブジェクト・コピーを削除し、そのコピーが使用していたメモリーを解放することです。キャッシュのメモリーを解放するには、次の2つの方法があります。

  • 明示的解放 – プログラムでOCIObjectFree()をコールして、キャッシュからオブジェクト・コピーを明示的に解放または削除します。この関数には、マークまたは確保されたオブジェクト・コピーのいずれかを(強制的に)解放するオプションがあります。OCICacheFree()をコールしてキャッシュ内のすべてのオブジェクト・コピーを解放することもできます。

  • 暗黙的解放 – キャッシュのメモリーが残り少なくなった場合は、確保解除済のオブジェクト・コピーとマーク解除済のオブジェクト・コピーの両方が、暗黙的に解放されます。マークされた、確保解除済のオブジェクトは、オブジェクト・コピーをフラッシュまたはマーク解除した場合にのみ、暗黙的解放の対象になります。


    関連項目:

    詳細は、「オブジェクト・キャッシュ・パラメータ」を参照してください。

メモリー管理を目的とする場合は、不要になったオブジェクトをアプリケーションで確保解除することが重要です。確保解除したオブジェクトはキャッシュから削除される対象になるので、必要なときにキャッシュのメモリーをスムーズに解放できます。

OCIでは、クライアント側キャッシュにある参照されていないオブジェクトを解放する関数は提供していません。

オブジェクト・コピーの変更

この項では、オブジェクト・コピーをマークする関数とマークを解除する関数を説明します。

オブジェクト・コピーのマーク

オブジェクト・コピーは、キャッシュ内でローカルに作成、更新および削除できます。(OCIObjectNew()をコールすることによって)キャッシュ内にオブジェクト・コピーを作成すると、オブジェクト・キャッシュでオブジェクト・コピーに挿入のマークが付けられます。そのため、このオブジェクト・コピーをフラッシュすると、オブジェクトがサーバーに挿入されます。

オブジェクト・コピーがキャッシュ内で更新された場合、ユーザーは、オブジェクト・コピーに更新のマークを付ける(OCIObjectMarkUpdate()をコールする)ことによって、オブジェクト・キャッシュに通知する必要があります。オブジェクト・コピーをフラッシュすると、サーバー内の対応するオブジェクトが、オブジェクト・コピーの値に更新されます。

オブジェクト・コピーが削除された場合、そのオブジェクト・コピーは(OCIObjectMarkDelete()をコールすることにより)オブジェクト・キャッシュ内で削除のマークが付けられます。オブジェクト・コピーをフラッシュすると、サーバー内の対応するオブジェクトが削除されます。マークされたオブジェクト・コピーのメモリーは、そのコピーをフラッシュして確保解除しないかぎり解放されません。プログラムで削除マーク付きのオブジェクトを確保すると、参照先のない参照を参照解除した場合と同様のエラーになります。

1つのオブジェクト・コピーを複数回変更した場合、そのコピーをフラッシュしたときにサーバーのオブジェクトに適用されるのは、最後の変更結果です。たとえば、オブジェクト・コピーを更新した後で削除した場合、オブジェクト・コピーをフラッシュすると、サーバーのオブジェクトは削除されます。同様に、オブジェクト・コピーの属性を複数回更新した場合、オブジェクト・コピーをフラッシュしたときにサーバーで更新されるのは、属性の最終的な値です。

プログラムでは、オブジェクト・コピーがオブジェクト・キャッシュにロードされている場合のみ、オブジェクト・コピーを更新済または削除済としてマークすることができます。

オブジェクト・コピーのマーク解除

オブジェクト・キャッシュ内のマークされたオブジェクト・コピーは、マーク解除できます。マークされたオブジェクト・コピーをマーク解除すると、オブジェクト・コピーに対して行った変更内容はサーバーにフラッシュされないことが保証されます。オブジェクト・キャッシュのオブジェクト・コピーに対して行ったローカルな変更内容は、取り消されません。

プログラムでオブジェクトをマーク解除するには、OCIObjectUnmark()をコールします。さらに、OCICacheUnmark()をコールして、特定の接続に対して、キャッシュ内のすべてのオブジェクト・コピーをマーク解除することもできます。

オブジェクト・コピーとサーバーとの同期化

この項では、キャッシュとサーバーの同期化操作(フラッシュ、リフレッシュ)を説明します。

変更をサーバーにフラッシュ

オブジェクト・コピーをフラッシュすると、キャッシュ内のマークされたオブジェクト・コピーに対して行ったローカルな変更が、サーバーに書き込まれます。OCIObjectFlush()をコールして、単一のオブジェクト・コピーをフラッシュできます。OCICacheFlush()をコールして、キャッシュ内のすべてのマークされたオブジェクト・コピーをフラッシュするか、リストに選択されているマークされたオブジェクト・コピーをフラッシュできます。OCICacheFlush()は、特定のサービス・コンテキストに関連付けられたオブジェクトをフラッシュします。「OCICacheFlush()」を参照してください。

オブジェクト・コピーをフラッシュしたら、マークを解除します。(フラッシュ後にオブジェクトはサーバーでロックされます。そのため、キャッシュ内のオブジェクト・コピーはロック状態とマークされます。)


注意:

OCIObjectFlush()操作では、複数のオブジェクトがフラッシュされる場合でも、サーバー・ラウンドトリップは1回のみです。

コールバック関数(OCICacheFlush()コールのオプションの引数)によって、ある型の使用済オブジェクトのみをフラッシュできます。目的のオブジェクトのみを戻すコールバックを定義します。この場合でも、フラッシュに対し、サーバー・ラウンドトリップが1回のみ発生します。

OCICacheFlush()のデフォルト・モードでは、オブジェクトは使用済とマークされるようにフラッシュされます。このフラッシュ操作のパフォーマンスは、環境ハンドル内でOCI_ATTR_CACHE_ARRAYFLUSH属性を設定すると、非常に向上します。

ただし、OCI_ATTR_CACHE_ARRAYFLUSH属性は、オブジェクトがフラッシュされる順序が重要でない場合にのみ使用することができます。この属性が有効なときは、使用済オブジェクトはまとめてグループ化され、サーバーによる表の更新が効率的に行われるような方法でサーバーに送信されます。この属性が有効なときは、オブジェクトが使用済としてマークされる順序の維持は保証されません。

オブジェクト・コピーのリフレッシュ

オブジェクト・コピーをリフレッシュすると、サーバー内の対応するオブジェクトの最新値が、オブジェクト・コピーに再ロードされます。最新値は、その他のコミット済トランザクションでの変更や、同じトランザクションで(オブジェクト・キャッシュを介さずに)直接サーバー内で行った変更を含む場合があります。プログラムでは、SQL DMLまたはトリガー、ストアド・プロシージャを使用して、サーバー内のオブジェクトを直接変更できます。

プログラムで、マークされたオブジェクト・コピーをリフレッシュするには、まずオブジェクト・コピーをマーク解除する必要があります。確保解除したオブジェクト・コピーは、リフレッシュすると(つまりキャッシュ全体をリフレッシュすると)、解放されます。

プログラムで単一のオブジェクト・コピーをリフレッシュするには、OCIObjectRefresh()をコールします。または、OCICacheRefresh()をコールして、キャッシュ内のすべてのオブジェクト・コピー、トランザクションでロードしたすべてのオブジェクト・コピー(つまり、recentまたはlatestオプションを指定して確保したオブジェクト・コピー)、またはリストに選択されたオブジェクト・コピーのいずれかをリフレッシュできます。

オブジェクトをサーバーにフラッシュすると、トリガーを起動してサーバー内のさらに多くのオブジェクトを変更できます。その場合、オブジェクト・キャッシュ内にある(トリガーによって変更したオブジェクトと)同一のオブジェクトは最新の状態ではなくなり、リフレッシュしないとロックまたはフラッシュできません。

各種のメタ属性フラグおよびオブジェクト継続時間は、表14-1で説明するとおり、リフレッシュされた後で変更されます。

表14-1 リフレッシュ操作後のオブジェクト属性

オブジェクト属性 リフレッシュ後の状態

既存

適切な値に設定

確保済

変更なし

フラッシュ済

リセット

割当て時間

変更なし

確保継続時間

変更なし


リフレッシュ操作の間、オブジェクト・キャッシュは新しいデータをオブジェクト・コピーのトップレベルのメモリーにロードし、トップレベルのメモリーを再利用します。オブジェクト・コピーのトップレベルのメモリーには、オブジェクトの表内格納属性が含まれています。ただし、オブジェクト・コピーの表外格納属性用のメモリーは、解放して再配置できます。これは、表外格納属性のサイズが可変であるためです。


関連項目:

オブジェクト・メモリーの詳細は、「インスタンスのメモリー・レイアウト」を参照してください。

オブジェクトのロック

この項では、オブジェクトのロックに関連するOCI関数について説明します。

ロック・オプション

オブジェクトを確保すると、オブジェクトをロックするか、またはロック・オプションを使用しないかを指定できます。オブジェクトをロックすると、サーバー側のロックが取得されるため、他のユーザーはオブジェクトを変更できなくなります。ロックが解除されるのは、トランザクションがコミットまたはロールバックする場合です。次に、各種のロック・オプションを示します。

  • ロック・オプションOCI_LOCK_NONEは、ロックなしでオブジェクトを確保するようにキャッシュに指示します。

  • ロック・オプションOCI_LOCK_Xは、ロックを取得した後でのみオブジェクトを確保するようにキャッシュに指示します。オブジェクトが現在別のユーザーによってロックされている場合、このオプションによる確保コールは、ロックが取得できるまで待機してから、コール元に戻ります。これは、SELECT FOR UPDATE文の実行に相当します。

  • ロック・オプションOCI_LOCK_X_NOWAITは、ロックを取得した後でのみオブジェクトを確保するようにキャッシュに指示します。OCI_LOCK_Xオプションとは異なり、OCI_LOCK_X_NOWAITオプションによる確保コールは、オブジェクトが現在別のユーザーによってロックされている場合、待機しません。これは、SELECT FOR UPDATE WITH NOWAIT文の実行に相当します。

更新するためのオブジェクトのロック

プログラムでは、オプションでOCIObjectLock()をコールして、更新するオブジェクトをロックできます。このコールは、データベースのオブジェクトに対する行ロックの実行をオブジェクト・キャッシュに指示します。これは、次の文の実行と類似しています。

SELECT NULL FROM t WHERE REF(t) = :r FOR UPDATE

この文では、tは、ロックするオブジェクトを格納しているオブジェクト表であり、rはオブジェクトを識別するREFです。OCIObjectLock()をコールすると、オブジェクト・キャッシュ内のオブジェクト・コピーがロック状態とマークされます。

オブジェクトのグラフまたはオブジェクトの集合をロックするには、オブジェクトごとにOCIObjectLock()のコールが必要なため、数回のコールが必要です。配列確保のOCIObjectArrayPin()コールを使用すると、パフォーマンスが向上します。

オブジェクトをロックすることにより、キャッシュのオブジェクトが最新のものであることをアプリケーションで保証します。オブジェクトがアプリケーションでロックされている間は、その他のトランザクションはそのオブジェクトを変更できません。

トランザクションの最後には、すべてのロックがサーバーによって自動的に解放されます。オブジェクト・コピーのロック状態インジケータはリセットされます。

NOWAITオプションを使用したロック

ロックしようとしているオブジェクトが、現在別のユーザーによってロックされている場合があります。この場合、アプリケーションはブロックされます。

オブジェクトをロックする際にブロッキングを避けるためには、アプリケーションでOCIObjectLock()コールのかわりにOCIObjectLockNoWait()コールを使用できます。この関数では、別のユーザーによるロックのためオブジェクトをロックできない場合は、すぐにエラーが戻されます。

NOWAITオプションは、OCI_LOCK_X_NOWAITの値をロック・オプション・パラメータとして渡すことで、コールを確保するためにも利用できます。

コミット時ロックの実装

OCIアプリケーションにコミット時ロックを実装するには、2つのオプションを使用します。コミット時ロックでは、トランザクションによって、オブジェクト・キャッシュ内のオブジェクトの変更とフラッシュ、および変更のコミットが正常に行われることを想定しています。

コミット時ロックのオプション1

第1のコミット時ロック・オプションは、シリアライズ可能なレベルでトランザクションを実行するOCIアプリケーションのためのオプションです。

OCIでは、オブジェクト・キャッシュ内のオブジェクトをロックせずに参照解除して確保し、キャッシュ内でそのオブジェクトを(ロックせずに)変更し、使用済のオブジェクトをデータベースにフラッシュするコールをサポートしています。

トランザクションの開始以降、使用済オブジェクトが、別のコミット済トランザクションによって変更された場合、フラッシュ操作の間に、シリアライズ不能トランザクションのエラーが戻されます。トランザクションの開始以降、別のトランザクションで変更された使用済オブジェクトがない場合は、トランザクションによって変更内容はデータベースに正常に書き込まれます。


注意:

OCITransCommit()は、使用済オブジェクトをデータベースにフラッシュしてから、トランザクションをコミットします。

この機能により、コミット時ロック・モデルが効果的に実装されます。

コミット時ロックのオプション2

アプリケーションでは、オブジェクトの変更検出モードを使用可能に切り替えられます。この操作を行うには、環境ハンドルのOCI_ATTR_OBJECT_DETECTCHANGE属性の値にTRUEを設定します。

このモードがアクティブのときは、別のオブジェクトがコミットしたトランザクションによってサーバー内で変更されているオブジェクトをフラッシュしようとすると、アプリケーションにORA-08179エラー「並行性チェックに失敗しました」が戻されます。この後、アプリケーションではこのエラーを適切な方法で処理できます。

オブジェクト・アプリケーションでのコミットおよびロールバック

トランザクションをコミットすると(OCITransCommit())、すべてのマークされたオブジェクトがサーバーにフラッシュされます。トランザクション継続時間を指定して確保したオブジェクト・コピーは、確保解除されます。

トランザクションをロールバックすると、すべてのマークされたオブジェクトがマーク解除されます。トランザクション継続時間を指定して確保したオブジェクト・コピーは、確保解除されます。

オブジェクト継続時間

メモリー内に空き領域を確保するために、オブジェクト・キャッシュは、可能なときにはいつでもオブジェクトのメモリーの再利用を試みます。オブジェクト・キャッシュは、オブジェクトの存続期間(割当て時間)の期限が切れるか、またはオブジェクトの確保継続時間の期限が切れたときに、オブジェクトのメモリーを再利用します。割当て時間は、オブジェクトがOCIObjectNew()で作成されたときに設定され、確保継続時間は、オブジェクトがOCIObjectPin()で確保されたときに設定されます。期間値のデータ型はOCIDurationです。


注意:

オブジェクトの確保継続時間は、オブジェクトの割当て時間より長くは設定できません。

オブジェクトの割当て時間が終わりに達すると、オブジェクトは自動的に削除され、メモリーが再使用可能になります。確保継続時間はオブジェクトのメモリーを再利用できる時期を示し、キャッシュが一杯になるとメモリーは再利用されます。

OCIでは、次の2つの事前定義済の継続時間をサポートします。

  • トランザクション(OCI_DURATION_TRANS)

  • セッション(OCI_DURATION_SESSION)

トランザクション継続時間は、包含するトランザクションが終了(コミットまたは終了)したときに期限が切れます。セッション継続時間は、セッションまたは接続が終了した時点で期限切れになります。

アプリケーションでは、OCIObjectUnpin()を使用してオブジェクトを明示的に確保解除できます。個々のオブジェクトの明示的な確保解除を最小限にするには、関数OCICacheUnpin()を使用して、オブジェクト・キャッシュ内で現在確保済のすべてのオブジェクトを確保解除します。デフォルトでは、すべてのオブジェクトは、確保継続時間終了時に確保を解除されます。

継続時間例

表14-2は、アプリケーションで、異なる継続時間を使用する方法を示しています。このアプリケーションでは、1つの接続と3つのトランザクションで、4つのオブジェクトを作成または確保しています。最初の列は、相対的な時間インジケータです。2番目の列はデータベースで実行されるアクションを示し、3番目の列はそのアクションを実行する関数を示しています。残りの列はアプリケーションの各ポイントでの各種オブジェクトの状態を示しています。

たとえば、オブジェクト1は、T2で期間を接続継続時間として作成されてから、接続が終了するT19まで存在します。オブジェクト2は、T6でフェッチされた後、期間をトランザクション継続時間としてT7で確保され、トランザクションがコミットされるT9まで確保されたままとなります。

表14-2 割当て時間および確保継続時間の例

時間 アプリケーションのアクション 関数 オブジェクト1 オブジェクト2 オブジェクト3 オブジェクト4

T1

接続を確立する

-

-

-

-

-

T2

オブジェクト1を作成する - 割当て時間 = 接続

OCIObjectNew()


既存

-

-

-

T5

トランザクション1を開始する

OCITransStart()


既存

-

-

-

T6

SQL - REFをオブジェクト2にフェッチする

-

既存

-

-

-

T7

オブジェクト2を確保する - 確保継続時間 = トランザクション

OCIObjectPin()


既存

確保済

-

-

T8

アプリケーション・データを処理する

-

既存

確保済

-

-

T9

トランザクション1をコミットする

OCITransCommit()


既存

確保解除

-

-

T10

トランザクション2を開始する

OCITransStart()


既存

-

-

-

T11

オブジェクト3を作成する - 割当て時間 = トランザクション

OCIObjectNew()


既存

-

既存

-

T12

SQL - REFをオブジェクト4にフェッチする

-

既存

-

既存

-

T13

オブジェクト4を確保する - 確保継続時間 = 接続

OCIObjectPin()


既存

-

既存

確保済

T14

トランザクション2をコミットする

OCITransCommit()


既存

-

削除済

確保済

T15

セッション1を終了する

OCIDurationEnd()


既存

-

-

確保済

T16

トランザクション3を開始する

OCITransStart()


既存

-

-

確保済

T17

アプリケーション・データを処理する

-

既存

-

-

確保済

T18

トランザクション3をコミットする

OCITransCommit()


既存

-

-

確保済

T19

接続を終了する

-

削除済

-

-

確保解除



関連項目:

  • これらの関数に渡すことができるパラメータ値の詳細は、第18章OCIObjectNew()およびOCIObjectPin()の説明を参照してください。

  • 割当て時間が期限切れになる前にオブジェクト・メモリーを解放する場合の詳細は、「オブジェクトの作成」を参照してください。


インスタンスのメモリー・レイアウト

メモリーのインスタンスは、インスタンスのトップレベル・メモリー・チャンク、NULLインジケータ構造体のトップレベル・メモリー、およびオプションとしていくつかの2次メモリー・チャンクで構成されています。たとえば、例14-1に定義されたDEPARTMENTという行の型を想定します。

例14-1 Department行のオブジェクト型の表現

CREATE TYPE department AS OBJECT
( dep_name      varchar2(20),
  budget        number,
  manager       person,            /* person is an object type */
  employees     person_array );   /* varray of person objects */

例14-2に、DEPARTMENTのC表現を示します。

例14-2 Department行のC表現

struct department
{
OCIString * dep_name;
OCINumber budget;
struct person manager;
OCIArray * employees;
);
typedef struct department department;

DEPARTMENTの各インスタンスには、dep_namebudgetmanageremployeesなどのトップレベル属性が含まれたトップレベル・メモリー・チャンクがあります。dep_name属性とemployees属性は、追加メモリー(2次メモリー・チャンク)へのポインタです。2次メモリーは、埋込みインスタンスのデータを入れるために使用されます(employeesのVARRAYやdep_nameの文字列など)。

NULLインジケータ構造体のトップレベル・メモリーには、インスタンスのトップレベル・メモリー・チャンクにある属性のNULL状態が入っています。例14-2では、NULL構造体のトップレベル・メモリーに、属性dep_namebudgetおよびmanagerのNULL状態と属性employeesのアトミックNULL状態が含まれています。

オブジェクト・ナビゲーション

この項では、OCIアプリケーションでオブジェクト・キャッシュ内のオブジェクトのグラフをナビゲートする方法を説明します。

単純なオブジェクト・ナビゲーション

例14-1および例14-2では、アプリケーションで取り出したオブジェクトは単純なオブジェクトであり、その属性はすべてスカラー値でした。アプリケーションで、別のオブジェクトへのREFである属性を持つオブジェクトを取り出す場合は、OCIコールを使用してオブジェクト・グラフを横断し、参照対象のインスタンスにアクセスできます。

たとえば、次の宣言でデータベースに新しい型を定義したとします。

CREATE TYPE person_t AS OBJECT
(  name          VARCHAR2(30),
  mother          REF person_t,
  father          REF person_t);

person_tオブジェクトのオブジェクト表は、次の文を使用して作成します。

CREATE TABLE person_table OF person_t;

これでperson_t型のインスタンスをこの型指定表に格納できます。person_tの各インスタンスには、同じ表に格納される他の2つのオブジェクトへの参照が含まれています。NULL参照は、親に関する情報がないことを表します。

オブジェクト・グラフは、オブジェクト・インスタンス間のREFリンクを視覚的に表現したものです。たとえば、図14-2に、1オブジェクトから別のオブジェクトへのリンクを示すperson_tインスタンスのオブジェクト・グラフを示します。円はオブジェクトを表し、矢印は他のオブジェクトへの参照を表しています。矢印の隣のMとFは、それぞれ母と父を示しています。

図14-2 person_tインスタンスのオブジェクト・グラフ

図14-2の説明は次にあります
「図14-2 person_tインスタンスのオブジェクト・グラフ」の説明

この場合、各オブジェクトには、同じオブジェクトに関する2つの別のインスタンス(MおよびF)へのリンクがあります。これは、必ずしも当てはまるわけではありません。オブジェクトには、他のオブジェクト型へのリンクがある場合があります。他の型のグラフも使用可能です。たとえば、一連のオブジェクトをリンクしたリストとして実装した場合、オブジェクト・グラフは単純な連鎖として表示され、各オブジェクトは、リンクしたリスト内の前または次のオブジェクト、あるいはその両方を参照します。

この章の前半で説明した方法を使用して、person_tインスタンスへの参照を取り出し、次にそのインスタンスを確保できます。OCIには、1つのオブジェクトから別のオブジェクトへ参照をたどることでオブジェクト・グラフを横断できる機能があります。

たとえば、アプリケーションで前述のグラフのperson1インスタンスをフェッチし、pers_1として確保するとします。確保されると、アプリケーションでは、person1のmotherインスタンスにアクセスし、2回目のPINオペレーションでpers_2に確保することができます。

OCIObjectPin(env, err, pers_1->mother, OCI_PIN_ANY, OCI_DURATION_TRANS,
             OCI_LOCK_X, (OCIComplexObject *) 0, &pers_2);

この場合、2つ目のインスタンスを取り出すためのOCIのフェッチ操作は必要ありません。

アプリケーションでは、次に、person1のfatherインスタンスを確保するか、person2の参照リンクで操作できます。


注意:

NULLまたは参照先がないREFを確保しようとすると、OCIObjectPin()コールがエラーになります。

OCIナビゲーショナル関数

この項では、OCIナビゲーショナル関数をまとめて簡単に説明します。関数は一般的な機能別にグループ化してあります。


関連項目:

これらの各関数の詳細は、第18章を参照してください。

これらの関数の使用方法については、この章の初めの項で説明しています。

ナビゲーショナル関数は、機能の種類によって異なる接頭辞を付けるネーミング計画に従っています。

OCICache*() - キャッシュ操作の関数。

OCIObject*() - 個々のオブジェクトを操作する関数。

確保/確保解除/解放関数

オブジェクトの確保、確保解除または解放を行うには、表14-3に示す関数を使用します。

表14-3 確保関数、解放関数および確保解除関数

関数 用途

OCICacheFree()


キャッシュの全インスタンスを解放します。

OCICacheUnpin()


キャッシュまたは接続で永続オブジェクトの確保を解除します。

OCIObjectArrayPin()


参照の配列を確保します。

OCIObjectFree()


スタンドアロン・インスタンスを解放し、確保解除します。

OCIObjectPin()


オブジェクトを確保します。

OCIObjectPinCountReset()


オブジェクトの確保を解除して確保カウントを0 (ゼロ)にします。

OCIObjectPinTable()


継続時間を指定して表オブジェクトを確保します。

OCIObjectUnpin()


オブジェクトの確保を解除します。


フラッシュおよびリフレッシュ関数

変更したオブジェクトをサーバーにフラッシュするには、表14-4に示す関数を使用します。

表14-4 フラッシュおよびリフレッシュ関数

関数 用途

OCICacheFlush()


キャッシュ内の変更済永続オブジェクトをサーバーにフラッシュします。

OCIObjectFlush()


単一の変更済永続オブジェクトをサーバーにフラッシュします。

OCICacheRefresh()


キャッシュ内の確保済永続オブジェクトをリフレッシュします。

OCIObjectRefresh()


単一の永続オブジェクトをリフレッシュします。


マークおよびマーク解除関数

アプリケーションでメタ属性の1つを変更してオブジェクトのマークまたはマーク解除を行うには、表14-5 に示す関数を使用します。

表14-5 マークおよびマーク解除関数

関数 用途

OCIObjectMarkDeleteByRef()


REFの指定時にオブジェクトを削除済にマークします。

OCIObjectMarkUpdate()


オブジェクトに更新済(使用済)のマークを付けます。

OCIObjectMarkDelete()


オブジェクトに削除済のマークを付けるか、または、値インスタンスを削除します。

OCICacheUnmark()


キャッシュ内の全オブジェクトをマーク解除します。

OCIObjectUnmark()


指定のオブジェクトを更新済にマークします。

OCIObjectUnmarkByRef()


REFの指定時にオブジェクトを更新済にマークします。


オブジェクトのメタ属性アクセッサ関数

アプリケーションでオブジェクトのメタ属性にアクセスするには、表14-6に示す関数を使用します。

表14-6オブジェクトのメタ属性関数

関数 用途

OCIObjectExists()


インスタンスの存在状況を取得します。

OCIObjectFlushStatus()

インスタンスのフラッシュ状態を取得します。

OCIObjectGetInd()


インスタンスのNULLインジケータ構造体を取得します。

OCIObjectIsDirty()


オブジェクトに更新済のマークが付いているかどうか調べます。

OCIObjectIsLocked()


オブジェクトはロック状態かどうか調べます。


その他の関数

表14-7に示す関数は、OCIアプリケーションにその他のオブジェクト機能を提供します。

表14-7その他のオブジェクト関数

関数 用途

OCIObjectCopy()


1つのインスタンスを別のインスタンスにコピーします。

OCIObjectGetObjectRef()


指定のオブジェクトへの参照を戻します。

OCIObjectGetTypeRef()


インスタンスのTDOへの参照を取得します。

OCIObjectLock()


永続オブジェクトをロックします。

OCIObjectLockNoWait()


NOWAITモードでオブジェクトをロックします。

OCIObjectNew()


新規インスタンスを作成します。


型の変更とオブジェクト・キャッシュ

型名に基づいて型情報がリクエストされると、OCIは最新バージョンの型に対応する型記述子オブジェクト(TDO)を戻します。サーバーとオブジェクト・キャッシュは同期していないため、オブジェクト・キャッシュ内のTDOは最新ではない場合があります。

オブジェクトの確保時に、イメージのバージョンがTDOのバージョンと異なっている可能性があります。この場合、エラーが発生します。アプリケーションを停止するか、またはTDOをリフレッシュしてオブジェクトを再確保するかを判断するのはユーザーです。アプリケーションを続行すると、アプリケーションが失敗する可能性があります。これは、イメージとTDOのバージョンが同じ場合でも、アプリケーションで定義されたオブジェクト構造(つまり、C構造体)が型の新しいバージョンと互換性があるという保証がないためです。特に、サーバー内で型から属性が削除された場合にこれが当てはまります。

したがって、型の構造体を変更した場合は、変更された型のヘッダー・ファイルを再生成し、アプリケーションを変更し、再コンパイルおよび再リンクしてから、プログラムを再実行する必要があります。


関連項目:

「型の変更」

OCIでのXMLのサポート

Oracle XML DBでは、XMLTypeデータ型を使用したXMLインスタンスの格納および操作をサポートしています。これらのXMLインスタンスにアクセスするには、OCIをC DOM API for XMLと併用します。

アプリケーション・プログラムでは、サーバー・ハンドル、文ハンドルなどの通常のOCIハンドルを初期化し、その後XMLコンテキストを初期化する必要があります。アプリケーション・プログラムでは、バックエンドでXMLインスタンスを操作したり、クライアント側で新規インスタンスを作成できます。初期化されたXMLコンテキストは、すべてのC DOM関数で使用できます。

Oracle XML DBに格納されたXMLデータは、C DOM構造体xmldocnodeによってクライアント側でアクセスできます。この構造体は、OCI文のXML値のバインド、定義および操作に使用できます。


関連項目:

  • CでのXMLのサポートの詳細は、第23章を参照してください。

  • バイナリXMLの例を含む、XML用C APIの使用方法は、『Oracle XML DB開発者ガイド』を参照してください。

  • C用のXMLパーサーの詳細は、『Oracle XML Developer's Kitプログラマーズ・ガイド』を参照してください。

  • DOM C APIs for XMLの詳細は、Oracle XMLリファレンスを参照してください。


XMLコンテキスト

XMLコンテキストは、すべてのC DOM API関数における必須パラメータです。この不透明なコンテキストは、データ・エンコーディング、エラー・メッセージ言語などに関連する情報をカプセル化します。このコンテキストの内容は、XDKおよびOracle XML DBアプリケーションでは異なります。

Oracle XML DBの場合、XMLコンテキストを初期化および解放するための2つのOCI関数が提供されています。

xmlctx *OCIXmlDbInitXmlCtx (OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
       ocixmldbparam *params, ub4 num_params);

void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

サーバー上のXMLデータ

サーバー上のXMLデータは、OCI文のコールによって操作できます。他のオブジェクト・インスタンスと同様に、xmldocnodeを使用してXMLTypeの値をバインドおよび定義できます。サーバーからXMLデータを選択するには、OCI文を使用します。このデータは直接C DOM関数で使用できます。同様に、値を直接SQL文にバインドしなおすことができます。

OCI XML DB関数の使用

XMLコンテキストを初期化および終了するには、それぞれOCIXmlDbInitXmlCtx()関数およびOCIXmlDbFreeXmlCtx()関数を使用します。ヘッダー・ファイルocixmldb.hは統合C APIとともに使用されます。

例14-3は、C APIによる操作の実行方法を示すテスト例のコード・フラグメントです。

例14-3 C APIによるXMLコンテキストの初期化および終了

#ifndef S_ORACLE
#include <s.h>
#endif
#ifndef ORATYPES_ORACLE
#include <oratypes.h>
#endif
#ifndef XML_ORACLE
#include <xml.h>
#endif
#ifndef OCIXML_ORACLE
#include <ocixmldb.h>
#endif
#ifndef OCI_ORACLE
#include <oci.h>
#endif
#include <string.h>

typedef struct test_ctx {
        OCIEnv *envhp;
        OCIError *errhp;
        OCISvcCtx *svchp;
        OCIStmt *stmthp;
        OCIServer *srvhp;
        OCIDuration dur;
        OCISession *sesshp;
        oratext *username;
        oratext *password;
} test_ctx;

...
void main()
{
  test_ctx temp_ctx;
  test_ctx *ctx = &temp_ctx;
  OCIType *xmltdo = (OCIType *) 0;
  xmldocnode *doc = (xmldocnode *)0;
  ocixmldbparam params[1];
  xmlnode *quux, *foo, *foo_data, *top;
  xmlerr err;
  sword status = 0;
  xmlctx *xctx;
 ...
  /* Initialize envhp, svchp, errhp, dur, stmthp */
  ...
 
  /* Get an xml context */
  params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
  params[0].value_ocixmldbparam = &ctx->dur;
  xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1);

/* Do unified C API operations next */
...

/* Free the statement handle using OCIHandleFree() */
...
/* Free the allocations associated with the context */
OCIXmlDbFreeXmlCtx(xctx);
/* Free envhp, svchp, errhp, stmthp */
...
}

OCIクライアントからバイナリXMLへのアクセス

中間層とクライアント層では、バイナリのXML形式でXMLを生成、消費および処理できます。Cアプリケーションでは、XML DBリポジトリからデータをフェッチし、DOMを使用してXMLの更新を実行し、データベースに格納します。または、クライアント上で作成または入力されたXML文書に対して、XSLT、XQueryおよび他のユーティリティを使用できます。その後、出力XMLはXML DBに保存されます。

クライアント・アプリケーションは、バイナリのXML文書のエンコードまたはデコード中にトークン定義、XMLスキーマおよびDTDをフェッチするために、メタデータ・リポジトリ(通常はバックエンド・データベース)への接続(メタデータ接続)を必要とします。

リポジトリ・コンテキストは、専用接続または接続プールを使用して初期化されます。リポジトリ・コンテキストから取得した接続を使用して、トークン定義やXMLスキーマなどのメタデータがフェッチされます。これに対して、アプリケーションには、データベースとの間でデータ(XMLデータなど)の通常の転送に使用するデータ接続もあります。リポジトリ・コンテキストは、(1つ以上の)データ接続に明示的に関連付けられています。データ接続を使用してデータベースとの間でXMLデータが読書きされる場合、基礎となるエンコードまたはデコード操作中に、該当するリポジトリ・コンテキストがアクセスされます。必要に応じて、リポジトリからメタデータをフェッチするためにメタデータ接続が使用されます。

OCIアプリケーションからXMLデータへのアクセス

Cアプリケーションでは、OCIを使用してデータベースに存在する永続XMLにアクセスし、統合XML C APIを使用してフェッチしたXMLデータを操作できます。

クライアント・アプリケーションでは、次のステップを実行します。

  1. 通常のOCIハンドル(OCIEnvOCISvcCtxおよびOCIErrorなど)を作成します。

  2. バイナリのXMLメタデータをフェッチするためにリポジトリ・コンテキストを1つ以上作成します。

  3. リポジトリ・コンテキストをデータ接続に関連付けます。

  4. 変数をSELECT、INSERTおよびUPDATE文にバインドまたは定義します(xmldocnode)。

  5. SELECT、INSERTまたはUPDATE文を実行して、XML文書をフェッチまたは格納します。この時点で、クライアントOCIライブラリがデータベース・バックエンドと相互作用し、必要なXMLスキーマ、DTD、トークン定義などをフェッチします。

  6. 統合C APIを使用してXMLデータ(DOM)を操作します。

リポジトリ・コンテキスト

OCIBinXmlReposCtxは、リポジトリ・コンテキストのデータ構造です。クライアント・アプリケーションでは、メタデータ・リポジトリに接続情報を提供することで、このコンテキストを作成します。アプリケーションでは、複数のリポジトリ・コンテキストを作成して複数のトークン・リポジトリに接続できます。リポジトリ・コンテキストは、データ接続(OCISvcCtx)に明示的に関連付けられます。システムがデータ接続との間でデータをエンコードまたはデコードするためにメタデータをフェッチする必要がある場合は、該当するメタデータにアクセスします。

アプリケーションでは、OCIEnvごとに1つリポジトリ・コンテキストを作成することをお薦めします。これにより、マルチスレッド・アプリケーションの同時実行性が向上します。

リポジトリ・コンテキストは、専用OCI接続またはOCI接続プールから作成できます。

専用OCI接続からのリポジトリ・コンテキストの作成

OCIBinXmlCreateReposCtxFromConn()は、指定した専用OCI接続を使用してリポジトリ・コンテキストを作成します。OCI接続はメタデータ・アクセスでのみ使用されるため、アプリケーションの別のシナリオでは使用しないでください。また、この接続へのアクセスはシリアライズされています。つまり、複数のスレッドが同じ接続を使用しようとしている場合、アクセスは一度に1つのスレッドに制限されます。次の項で説明するように、スケーラビリティの理由により、アプリケーションでは接続プールを使用してリポジトリ・コンテキストを作成することをお薦めします。

注意: データに使用するのと同じ接続を渡すことも可能です。ただし、この場合、クライアント・システムがSELECTやINSERTのような別の操作の一部を実行する間にメタデータ・リポジトリに接続すると、特定の状況でエラーになる可能性があります。

接続プールからのリポジトリ・コンテキストの作成

OCIBinXmlCreateReposCtxFromCPool()では、接続プールからリポジトリ・コンテキストが作成されます。アプリケーションからバックエンド・リポジトリにアクセスする間に、プール内の使用可能接続が使用されます。さらに、この接続はメタデータ操作の完了直後にプールに解放されます。マルチスレッド・アプリケーションのシナリオには、接続プールを使用することをお薦めします。様々なスレッドがプール内の異なる接続を使用し、完了直後に解放できます。このアプローチでは、少数の物理接続で高度な拡張性と同時実行性が実現できます。

リポジトリ・コンテキストとデータ接続の関連付け

OCIBinXmlSetReposCtxForConn()では、リポジトリ・コンテキストがOCISvcCtx *により記述されたデータ接続に関連付けられます。複数のデータ接続で同じリポジトリ・コンテキストを共有できますが、リポジトリへのアクセスがシリアル化される可能性があります(専用接続ベースの場合)。システムがエンコードまたはデコード操作のためにメタデータをフェッチする必要がある場合は、OCIEnvOCISvcCtxのペアから該当するリポジトリ接続を参照し、それを使用して必要なメタデータをフェッチします。

XMLTypeエンコーディング形式のプリファレンス設定

デフォルトでは、データベースに送信されたXMLデータは、ソース形式(DBから読取り済の場合)などの特定の内部基準に基づいて、可能な形式(テキスト、オブジェクト・リレーショナルまたはバイナリのXML)のいずれかでエンコードされます。OCIBinXmlSetFormatPref()は、エンコーディング形式のプリファレンスを設定する明示的なメカニズムを提供します。将来は、デフォルト形式をバイナリのXMLにできるようになりますが、この関数を使用すると必要に応じてデフォルト形式を上書きできます。

接続プールの使用例

XML DBのマニュアルに示したこの例で、接続プールからリポジトリ・コンテキストを作成してデータ接続に関連付ける方法を示します。データベースはローカルで、テストは単一スレッド・モードで実行されます。


関連項目:

Oracle XML DBによるXML用OCIおよびC APIの使用方法は、『Oracle XML DB開発者ガイド』を参照してください。