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

この章では、オブジェクトをOracle Databaseで操作するためのOCIの機能を紹介します。

また、OCIのオブジェクト・ナビゲーショナル関数コール、型進化およびXMLのサポートについても説明します。

この章には次のトピックが含まれます:

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

オブジェクト・キャッシュは、オブジェクトの参照とメモリー管理をサポートするクライアント側のメモリー・バッファです。

これは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 (ゼロ)のオブジェクトのことです。

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

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

図22-1の説明が続きます
「図22-1 オブジェクト・キャッシュ」の説明

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

22.1.1 キャッシュの一貫性

オブジェクト・キャッシュ内のオブジェクト・コピーと、データベース内で対応するオブジェクトとの間における値の一貫性は、自動的にはメンテナンスされません。

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

ノート:

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

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

オブジェクト・キャッシュには、環境ハンドルの属性である、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()関数を使用します。

関連項目:

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

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

関連項目:

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

22.1.3.1 確保と確保解除について

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

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

22.1.3.2 解放について

オブジェクトの解放について説明します。その内容を説明します。

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

22.1.3.3 マークとマーク解除について

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

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

22.1.3.4 フラッシュについて

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

それによって、オブジェクト・キャッシュ内のコピーのマークが解除されます。

22.1.3.5 リフレッシュについて

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

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

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

struct Person {
OCINumber salary;
OCIString *name;
}

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

関連項目:

OCIObjectRefresh()

22.1.4 オブジェクト・コピーのロードと削除について

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

22.1.4.1 オブジェクト・コピーの確保について

オブジェクト・キャッシュ内の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
22.1.4.2 オブジェクト・コピーの確保解除について

プログラムで使用しないオブジェクト・コピーは、確保解除できます。

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

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

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

22.1.4.3 オブジェクト・コピーの解放について

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

キャッシュのメモリーを解放するには、次の2つの方法があります。

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

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

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

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

関連項目:

22.1.5 オブジェクト・コピーの変更について

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

22.1.5.1 オブジェクト・コピーのマークについて

オブジェクト・コピーは、キャッシュ内でローカルに作成、更新および削除できます。

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

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

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

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

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

22.1.5.2 オブジェクト・コピーのマーク解除について

オブジェクト・キャッシュ内のマークされたオブジェクト・コピーは、マーク解除できます。

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

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

22.1.6 オブジェクト・コピーとサーバーとの同期化について

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

22.1.6.1 変更のサーバーへのフラッシュについて

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

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

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

ノート:

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

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

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

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

22.1.6.2 オブジェクト・コピーのリフレッシュについて

オブジェクト・コピーをリフレッシュすると、サーバー内の対応するオブジェクトの最新値が、オブジェクト・コピーに再ロードされます。

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

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

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

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

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

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

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

存在

適切な値に設定

確保済

変更なし

フラッシュ済

リセット

割当て時間

変更なし

確保継続時間

変更なし

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

関連項目:

22.1.7 オブジェクトのロック

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

22.1.7.1 ロック・オプション

オブジェクトを確保すると、オブジェクトをロックするか、またはロック・オプションを使用しないかを指定できます。

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

  • ロック・オプション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文の実行に相当します。

22.1.7.2 更新するためのオブジェクトのロックについて

プログラムでは、オプションでOCIObjectLock()をコールして、更新するオブジェクトをロックできます。

このコールは、データベースのオブジェクトに対する行ロックの実行をオブジェクト・キャッシュに指示します。これは、次の文の実行と類似しています。

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

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

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

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

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

22.1.7.3 NOWAITオプションを使用したロックについて

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

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

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

22.1.7.4 コミット時ロックの実装について

OCIアプリケーションにコミット時ロックを実装するには、2つのオプションを使用します。

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

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

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

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

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

ノート:

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

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

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

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

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

関連項目:

OCITransCommit()

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

トランザクションをコミットすると(OCITransCommit())、すべてのマークされたオブジェクトがサーバーにフラッシュされます。

トランザクション継続時間を指定して確保したオブジェクト・コピーは、確保解除されます。

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

関連項目:

OCITransCommit()

22.1.9 オブジェクト継続時間

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

割当て時間は、オブジェクトがOCIObjectNew()で作成されたときに設定され、確保継続時間は、オブジェクトがOCIObjectPin()で確保されたときに設定されます。期間値のデータ型はOCIDurationです。

ノート:

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

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

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

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

  • セッション(OCI_DURATION_SESSION)

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

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

この項には次のトピックが含まれます: 継続時間例

22.1.9.1 継続時間例

アプリケーションで、異なる継続時間を使用する方法を示します。

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

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

表22-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

接続を終了する

-

削除済

-

-

確保解除

関連項目:

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

メモリーのインスタンスは、インスタンスのトップレベル・メモリー・チャンク、NULLインジケータ構造体のトップレベル・メモリー、およびオプションとしていくつかの2次メモリー・チャンクで構成されています。

たとえば、例22-1に定義されたDEPARTMENTという行の型を想定します。

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

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

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

例22-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 */

例22-2 Department行のC表現

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

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

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

この項には次のトピックが含まれます: 単純なオブジェクト・ナビゲーション

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

アプリケーションで、別のオブジェクトへのREFである属性を持つオブジェクトを取り出す場合は、OCIコールを使用してオブジェクト・グラフを横断し、参照対象のインスタンスにアクセスできます。

例22-1および例22-2では、アプリケーションで取り出したオブジェクトは単純なオブジェクトであり、その属性はすべてスカラー値でした。

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

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

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

図22-2の説明が続きます
「図22-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()コールがエラーになります。

関連項目:

OCIObjectPin()

22.3 OCIナビゲーショナル関数

この項では、OCIナビゲーショナル関数をまとめて簡単に説明します。

関数は一般的な機能別にグループ化してあります。

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

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

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

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

関連項目:

これらの各関数の詳細は、「OCIのナビゲーショナル関数と型関数」を参照してください

22.3.1 確保/確保解除/解放関数について

確保関数、確保解除関数および解放関数をリストし、説明します。

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

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

関数 用途

OCICacheFree()

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

OCICacheUnpin()

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

OCIObjectArrayPin()

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

OCIObjectFree()

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

OCIObjectPin()

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

OCIObjectPinCountReset()

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

OCIObjectPinTable()

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

OCIObjectUnpin()

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

22.3.2 フラッシュおよびリフレッシュ関数について

フラッシュおよびリフレッシュ関数をリストし、説明します。

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

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

関数 用途

OCICacheFlush()

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

OCIObjectFlush()

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

OCICacheRefresh()

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

OCIObjectRefresh()

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

22.3.3 マークおよびマーク解除関数について

マークおよびマーク解除関数をリストし、説明します。

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

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

関数 用途

OCIObjectMarkDeleteByRef()

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

OCIObjectMarkUpdate()

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

OCIObjectMarkDelete()

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

OCICacheUnmark()

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

OCIObjectUnmark()

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

OCIObjectUnmarkByRef()

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

22.3.4 オブジェクトのメタ属性アクセッサ関数について

メタ属性アクセッサ関数をリストし、説明します。

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

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

関数 用途

OCIObjectExists()

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

OCIObjectGetInd()

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

OCIObjectIsDirty()

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

OCIObjectIsLocked()

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

22.3.5 その他の関数について

その他の関数をリストし、説明します。

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

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

関数 用途

OCIObjectCopy()

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

OCIObjectGetObjectRef()

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

OCIObjectGetTypeRef()

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

OCIObjectLock()

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

OCIObjectLockNoWait()

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

OCIObjectNew()

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

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

型名に基づいて型情報がリクエストされると、OCIは最新バージョンの型に対応する型記述子オブジェクト(TDO)を戻します。

サーバーとオブジェクト・キャッシュは同期していないため、オブジェクト・キャッシュ内のTDOは最新ではない場合があります。

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

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

関連項目:

型進化について