ここではCachedUpdatesについて説明します。
Delphi Professional 以上のユーザであれば、BDE(Borland Database
        Engine)で「キャッシュアップデート」という機能が使えるということを聞いたことがあるはずです。しかし、Delphiのマニュアルの説明不足のせいで、よく知らないために使わないでいる方も多いと思います。
通常は、データセット上のレコードを更新して、Postメソッドで更新を確定させると、その場でOracleサーバに対しUPDATE/INSERT/DELETE文が発行されますが、
TOracleDataSetがCachedUpdatesモードに設定されている場合は、Postメソッドによる更新の確定は、クライアントアプリケーションの内部に設けられたローカルの更新キャッシュに対して行われ、SQLの発行が(後回しに)遅延されます。
実際にOracleサーバ上のデータを更新するには、TOracleDataSetのApplyUpdatesメソッドを呼び出します。このとき、ローカルの更新キャッシュに蓄積されていた変更が、一括してOracleサーバに受け渡されます。
- 
            TOracleDataSet
- property
CachedUpdates:
boolean:
Trueにセットすると、データセットの更新をローカルにキャッシュします。 
 - property
 - TOracleSession * procedure
ApplyUpdates(const
DataSets: array of TOracleDataSet;
Commit: Boolean) :- データセットのローカル更新キャッシュに行われた更新内容を、SQLサーバに反映させます
 - master/detail
関係が定義されている場合、masterデータセットについてApplyUpdatesを行うことで、detailデータセットの更新キャッシュも反映されます - さらに、Commit=Trueの場合は、トランザクションをコミットします
 - procedure
CommitUpdates(DataSets): ApplyUpdates(DataSets, True)と同じです - procedure
CancelUpdates(const DataSets: array of TOracleDataSet):- データセットのローカル更新キャッシュをクリアします
 - 変更されていたレコードは元に戻り、挿入されていたレコードは消え、削除されていたレコードは復活します
 
 
 
CachedUpdatesのメリット
- サーバに負荷をかけないトランザクション制御
- CachedUpdatesモードでは、CancelUpdatesによって変更を取り消すことが可能です。そのため、ApplyUpdates/CancelUpdatesを使ってトランザクション制御が実現できます。しかも、Commit/Rollbackと異なり、CachedUpdates/CancelUpdatesは、SQLサーバの資源を全く消費しない点ですぐれています
 
 - バッチ:パフォーマンスの向上
- 一度に多数のレコードを更新する場合には、クライアントアプリケーションと、Oracleサーバの間の通信の発生回数を抑えることで、通信のオーバヘッドにかかる時間を節約することができます
 
 - オンライン:トランザクション継続時間の短縮
- 一般に、「長い」トランザクションによって、長時間にわたりレコードをロックすることは、レコードロックの競合を起こりやすくするため、デッドロックや、応答時間低下の原因となり得ます。CachedUpdatesを使うと、トランザクションの開始がApplyUpdatesが行われるまで遅延されるため、「長い」トランザクションが発生しにくくなります
 
 
CachedUpdatesのデメリット
- バッチ:ローカルシステム資源の消費
- ローカルに更新キャッシュを保持するためのメモリが必要なため、あまりに大量のレコードを一度に更新すると、メモリが不足する恐れがあります。一般的に言って、CachedUpdatesでキャッシュするレコード件数が、数十万件になるようなら、途中で更新を分割してApplyUpdatesするべきでしょう
 
 - オンライン:最新レコードの反映遅れ
- CachedUpdatesの性質上、どこかの端末で更新した最新データは、すぐにOracleのデータベースに反映されず、しばらくはその端末のローカルキャッシュに留まります。したがって、不特定多数のユーザによって更新され、つねに最新データの参照が必要であるようなデータを扱う場合には、CachedUpdatesによって更新を長時間キャッシュするのは避けるべきです。
 
 
CachedUpdatesの使用例: master/detail関係にあるテーブルの挿入
例えば、受注(Order)テーブルと、受注詳細(OrderDetail)テーブルという二つのテーブルに、注文書の内容を挿入するとします
- 注文番号を新たに採番する
 - 受注テーブルに1レコードを挿入し、(注文番号、顧客番号と、注文日付)をセット
 - 受注詳細テーブルに、受注した各製品ごとにレコードを挿入し(注文番号、注文書行番号、製品番号、受注数量)をセット
 
というシナリオを処理するオンラインアプリケーションを考えてみて下さい。注文詳細テーブルを1レコード更新するごとに、Oracleに更新を反映する必要は全くありません。データの更新は、注文書作成が完了した時に1回でいいはずです。
- 二つのテーブルそれぞれに挿入するデータを編集するために二つのデータセットを用意します
 
//OrderQuery.SQL = 'SELECT Order.ROWID, Order.* FROM Order WHERE 0=1' //OrderDetailQuery.SQL = 'SELECT OrderDetail.ROWID, OrderDetail.* FROM OrderDetail WHERE 0=1'
注文入力フォームを開いたらまず上記の例のようにWHERE条件をFalseのままにOrderQueryを開き、即座にAppendして、空のレコードを作ります。これをデータベース対応コンポーネントでエディットするとよいでしょう。
顧客番号を入力するEditBox(実際の業務の場合は50音順検索やリストからの選択機能が必要でしょう)があり、DetailQueryはDBGridコンポーネントに関連付けられていて、製品番号と受注数量の一覧編集を行うことでしょう。
…と、前置きが長くなりましたが、「注文入力」ボタンのコードは例えばこんな感じです。
  //OrderQuery.CachedUpdates = True
  //OrderDetailQuery.CachedUpdates = True
  procedure SubmitButtonClick(Sender: TObject);
  var
    NewOrderNumber: integer;
    i: integer;
  begin
    //まず、注文番号を採番
    SequenceQuery.SQL = 'SELECT OrderNumSeq.NextVal NewOrderNumber FROM DUAL';
    SequenceQuery.Open;
    NewOrderNumber := SequenceQuery.Field('NewOrderNumber').AsInteger;
    //受注テーブルにキー項目をセット
    with OrderQuery do begin
      Edit;
      Field('OrderNumber').AsInteger := NewOrderNumber;
      Post;
    end;
    //受注詳細テーブルのキー項目をセット
    with OrderDetailQuery do begin
      i := 0;
      First;
      while not Eof do begin
        Edit;
        Field('OrderNumber').AsInteger := NewOrderNumber;
        Field('OrderDetailNumber').AsInteger := i;
        Post;
        Next;
        Inc(i);
      end;
    end;
    //ここまでの更新は、ローカルにキャッシュされる
    //ここでまとめて更新をサーバに反映する
    OracleSession.ApplyUpdates([OrderQuery, OrderDetailQuery], True);
    //(...以下省略...たとえばフォームを閉じたり、クリアしたり…)
  end;
			