DelphiでOO4Oを使用する


OO4O というのは、Oracle Object For OLE という、Windows向けの Oracle 操作用オブジェクトのことです。Oracle データベースにアクセスする方法は、ODBC を使ったり、ADO を使ったりと、いろいろなやり方がありますが、おそらくその中で最も高速なアクセス方法が、この OO4O を使用するやり方でしょう。というのは、 OO4O は Oracle ネイティブなオブジェクトなので、これをインタフェイスとして直接 Oracle の多くの機能を利用することができるからです。ODBCなどを仲介すると、それだけでアクセスが遅くなる上、Microsoft などから提供されている ODBCドライバでは、Oracle の機能を必要最低限しか利用できないこともあります(それでも十分なところはありますが)。

では、その OO4O の使用方法を。

まず、OO4O がマシンにインストールされていることを確認。これは、Oracleをインストールすれば、大抵勝手にインストールされているはずです。そうすると、メインメニューの [プロジェクト] → [タイプライブラリの取り込み] のリストの中に、「Oracle InProcServer 3.0 Type Library」という項目が見えると思います。それを選択して [ユニットの作成] ボタンを押します。すると、「OraInProcServer_TLB.pas」 というユニットができるので、そのユニットがプロジェクトに追加されたら、それをプロジェクトから削除します。というのは、このままだと、このユニットはコンパイルすることができないんですね。なので、できたTLBというユニットファイルは、メソッドやプロパティの書式を参考にする為だけに作っておくものとします。

しかし、本当はこれでそのままコンパイルが通って利用できなくてはおかしいはずです。これについて何か情報をお持ちの方は、ご教授いただけると非常に嬉しいです(笑)

さて、まず OO4O オブジェクトとなる変数を Variant型 で宣言しておきます。で、初期化する部分で、CreateOleObject しておきます。オブジェクト名は「OracleInProcServer.XOraSession」です。

var
 
OraSession: Variant;

begin

  // OO4O のインタフェイスを作成する
  OraSession:= CreateOleObject('OracleInProcServer.XOraSession');

end;
 

これで、OraSession という変数から、OO4O のプロパティやメソッドを利用できるようになりました。

次に、データベースを開かなければ、データベースを利用することはできません。データベースを開くのは、OpenDatabase というプロパティを使用します。

var
  OraDatabase: Variant;

begin

  :
  :

  // Oracleデータベースを開く
  OraDatabase:= OraSession.OpenDatabase['', 'SCOTT/TIGER', 0];

end;

OpenDatabase の第一引数はデータベース名(サービス名)、第二引数は接続文字列(’ユーザ名/パスワード’の形)、第三引数は、データベース生成時のオプションです(普通は0でOK)。

ここで、OpenDatabase というのはプロパティだということに注意してください。先程作成したTLB.pas ファイルにある宣言を参照すると分かりますが、プロパティにセットする引数は、大括弧 [ ] で指定するようになっています。

これでできた データベース変数を使用して、各種SQL文が発行できるようになります。SELECT文でEMPテーブルを取得して、それを文字列の配列に格納する例を次に示します。

var
  OraDynaset: Variant;

  iCnt, iRec, iFld: Integer;

  iFieldNum: Integer;
  sFieldNames: Array of String;

  iRecordNum: Integer;
  sValues: Array of Array of String;

begin

  :
  :

  // SQL文の発行
  OraDynaset:= OraDatabase.CreateDynaset['SELECT * FROM EMP', 0];

  // フィールド数取得
  iFieldNum:= OraDynaset.Fields.Count;

  // フィールド数設定
  SetLength(FieldNames, iFieldNum);

  // フィールド名取得
  for iCnt:= 0 to iFieldNum-1 do
  begin
    iFieldNames[iCnt]:= OraDynaset.Fields[iCnt].Name;
  end;

  // レコード数取得
  iRecordNum:= OraDynaset.RecordCount;

  // レコード数設定
  SetLength(sValues, iFieldNum, iRecordNum);

  // レコード取得
  OraDynaset.MoveFirst;
  for iRec:= 0 to iRecordNum-1 do
  begin
    for iFld:= 0 to iFieldNum-1 do
    begin
      try
        sValues[iFld][iRec]:= OraDynaset.Fields[iFld].Value;
      except
        sValues[iFld][iRec]:= '';
      end;
    end;
    OraDynaset.MoveNext;
  end;

end;

CreateDynaset の第一引数はSQL文ですが、この文末にセミコロン「;」をつける必要はありません。むしろ、セミコロンがあるとエラーになってしまいますので、この処理の前に、セミコロンがあったら削る、という処理を入れておくと良いかもしれませんね。第二引数はSQLオプションですが、これは、特に必要が無い限りは0でOKです。

SQL文でも、データベースを更新するようなもの(INSERT、UPDATE、DELETEなど)は、SELECTとは異なる使い方をします。それは、更新系のSQL文の場合は、最後にコミットする(処理を完了する)必要があるからです。また、SELECT以外は、ExecuteSQL というメソッドを使用します。その例を次に示します。

begin

  :
  :

  //データ更新
  OraDatabase.BeginTrans;
  try
    OraDatabase.ExecuteSQL('UPDATE EMP SET ... ');
    OraDatabase.CommitTrans;//成功時はCommitする
  except
    on E: EOleError do
    begin
      OraDatabase.Rollback;//失敗時はRollbackする
    end;
  end;

end;

ExecuteSQL に失敗すると、OLEエラーが発生するので、それを try... except 節でトラップしてロールバックするようにすると確実です。

使い終わったデータベースは閉じて、解放します。もともと Variant型 なので、この変数に Unassigned を代入すれば、これらのオブジェクトは解放されます。

begin

  :
  :

  // データベースを閉じる
  OraDatabase.Close;

  // 使用し終わったら破棄
  OraDatabase:= Unassigned;
  OraDynaset:= Unassigned;

end;

Oracle 8 以降の場合、データベース接続をプールに溜めておいて、一度使用した接続を再利用することでアクセス時間を短縮するという機能が実装されています。手順は、CreateDatabasePool で接続プールを作成して、GetDatabaseFromPool で、接続を取得してそれを使用する、という感じになります。その一連の流れを次に示します。

begin

  :
  :

  // Oracleセッションの生成
  OraSession:= CreateOleObject('OracleInProcServer.XOraSession');

  // DB接続プールの生成
  OraSession.CreateDatabasePool(10,           // 初期のプールに溜めておく接続数
                                100,          // プールに溜めておく最大接続数
                                3000,         // 接続タイムアウト時間(msec)
                                '',           // データベース名
                                'SCOTT/TIGER',// 接続文字列
                                0);           // 接続オプション

  :
  :

  // プールからデータベース接続を取得する
  OraDatabase:= OraSession.GetDatabaseFromPool[300];

  :
  :  (ここに SQL文を発行する処理を書く)
  :
  :


  // 使用し終わったら破棄
  OraDatabase:= Unassigned;
  OraDynaset:= Unassigned;

end;

GetDatabaseFromPool の引数は接続のタイムアウト時間(ミリ秒)です。

ところで、接続プールを使用してSELECT以外のSQL文を実行するのは良くないらしいです。ので、SELECT以外(INSERT、UPDATEなど)を実行するときは、新たにクライアントセッションを作成して、そのセッションで実行する、という手順を踏みます。その例を次に示します。

var
 
UpdtSess: Variant;
  UpdtDb: Variant;

begin


  :
  :

  // 更新用のクライアントセッションを作成する
  UpdtSess:= FOraSession.Client.CreateSession['#' + OraSession.Name];

  // データベースを開く
  UpdtDb:= UpdtSess.OpenDatabase['', 'SCOTT/TIGER', 0];

  //データ更新
  UpdtDb.BeginTrans;
  try
    UpdtDb.ExecuteSQL('UPDATE ...');
    UpdtDb.CommitTrans;//成功時はCommitする
  except
    on E: EOleError do
    begin
      UpdtDb.Rollback;//失敗時はRollbackする
    end;
  end;

  :
  :

end
;

用済みの変数は Unassigned しておくのを忘れないようにしてください。

その他に OO4O で用意されているメソッドやプロパティも、同様の方法で利用できます。どんなメソッドやプロパティが利用できるかは、最初に作った TLB.pas ファイルの宣言文で確認できます。使用方法や意味などは、Oracle のマニュアルや、関連サイト( 例えば ここ )などを参考にしてください。


[ Delphi へ戻る ]