Tripletail::DB - DBIのラッパ

# NAME

Tripletail::DB - DBIのラッパ

# SYNOPSIS

      $TL->startCgi(
          -DB      => 'DB',
          -main        => \&main,
      );

      sub main {
        my $DB = $TL->getDB('DB');

        $DB->setDefaultSet('R_Trans');
        $DB->begin;

        my $sth = $DB->execute(q{SELECT a, b FROM foo WHERE a = ?}, 999);
        while (my $hash = $sth->fetchHash) {
            print $hash->{a};
        }
        $DB->commit;

        $DB->begin('W_Trans');
        $DB->execute(q{UPDATE counter SET counter = counter + 1 WHERE id = ?}, 1);
        $DB->commit;
      }

# DESCRIPTION

接続/切断は自動で行われる。

  手動で接続/切断する場合は、connect/disconnectを使う。

実行クエリの処理時間・実行計画・結果を記録するデバッグモード。
prepare/executeを分けない。fetchは分ける。
拡張プレースホルダ機能

        $db->execute(q{select * from a where mode in (??)}, ['a', 'b'])

  と記述すると、

        $db->execute(q{select * from a where mode in (?, ?)}, 'a', 'b')

  のように解釈される。

プレースホルダの値渡しの際に型指定が可能

        $db->execute(q{select * from a limit ??}, ['a', \'SQL_INTEGER'])

リクエスト処理完了後のトランザクション未完了やunlock未完了を自動検出
DBグループ・DBセット・DBコネクション

  Tripletail::DBでは、レプリケーションを利用してロードバランスすることを支援するため、 １つのDBグループの中に、複数のDBセットを定義することが可能となっている。 DBセットの中には、複数のDBコネクションを定義できる。

  更新用DBセット、参照用DBセット、などの形で定義しておき、プログラム中で トランザクション単位でどのDBセットを使用するか指定することで、 更新用クエリはマスタDB、参照用クエリはスレーブDB、といった 使い分けをすることが可能となる。

  DBセットには複数のDBコネクションを定義でき、複数定義した場合は プロセス単位でプロセスIDを元に1つのコネクションが選択される。 （プロセスIDを定義数で割り、その余りを使用して決定する。）

  同じDBグループの中の複数のDBセットで同じDBコネクション名が使用された場合は、 実際にDBに接続されるコネクション数は1つとなる。 このため、縮退運転時に参照用DBセットのDBコネクションを更新用の ものに差し替えたり、予め将来を想定して多くのDBセットに分散 させておくことが可能となっている。

  DBセットの名称はSET_XXXX(XXXXは任意の文字列)でなければならない。 DBコネクションの名称はCON_XXXX(XXXXは任意の文字列)でなければならない。

## DBIからの移行

TripletailのDBクラスはDBIに対するラッパの形となっており、多くのインタフェースはDBIのものとは異なる。 ただし、いつでも $DB->getDbh() メソッドにより元のDBIオブジェクトを取得できるので、DBIのインタフェースで利用することも可能となっている。

DBIのインタフェースは以下のようなケースで利用できる。ただし、DBIを直接利用する場合は、TLの拡張プレースホルダやデバッグ機能、トランザクション整合性の管理などの機能は利用できない。

ラッパに同等の機能が用意されていない場合。

  （例）$DB->{mysql_insertid}

高速な処理が必要で、ラッパのオーバヘッドを回避したい場合。

  DBIに対するラッパであるため、大量のSQLを実行する場合などはパフォーマンス上のデメリットがある。

DBIでのSELECTは、以下のように置き換えられる。

     # DBI
     my $sth = $DB->prepare(q{SELECT * FROM test WHERE id = ?});
     $sth->execute($id);
     while(my $data = $sth->fetchrow_hashref) {
     }
     # TL
     my $sth = $DB->execute(q{SELECT * FROM test WHERE id = ?}, $id);
     while(my $data = $sth->fetchHash) {
     }

TLではprepare/executeは一括で行い、prepared statement は利用できない。

INSERT・UPDATEは、以下のように置き換えられる。

     # DBI
     my $sth = $DB->prepare(q{INSERT INTO test VALUES (?, ?)});
     my $ret = $sth->execute($id, $data);
     # TL
     my $sth = $DB->execute(q{INSERT INTO test VALUES (?, ?)}, $id, $data);
     my $ret = $sth->ret;

prepare/executeを一括で行うのは同様であるが、executeの戻り値は$sthオブジェクトであり、影響した行数を取得するためには $sth->ret メソッドを呼ぶ必要がある。

プレースホルダの型指定は以下のように行う。

     # DBI
     my $sth = $DB->prepare(q{SELECT * FROM test LIMIT ?});
     $sth->bind_param(1, $limit, { TYPE => SQL_INTEGER });
     $sth->execute;
     # TL
     my $sth = $DB->execute(q{SELECT * FROM test LIMIT ??}, [$limit, \'SQL_INTEGER']);

TLの拡張プレースホルダ（??で表記される）を利用し、配列のリファレンスの最後に型をスカラのリファレンスの形で渡す。 拡張プレースホルダでは、複数の値を渡すことも可能である。

     # DBI
     my $sth = $DB->prepare(q{SELECT * FROM test LIMIT ?, ?});
     $sth->bind_param(1, $limit, { TYPE => SQL_INTEGER });
     $sth->bind_param(2, $offset, { TYPE => SQL_INTEGER });
     $sth->execute;
     # TL
     my $sth = $DB->execute(q{SELECT * FROM test LIMIT ??}, [$limit, $offset, \'SQL_INTEGER']);

最後にINSERTした行のAUTO_INCREMENT値の取得などは、拡張ラッパでは制御できないので、DBIのハンドラを直接利用する。

     # DBI
     my $id = $DB->{mysql_insertid};
     # TL
     my $id = $DB->getDbh()->{mysql_insertid};

BEGIN/COMMIT/ROLLBACKはDBIとほぼ同様である。ただし、TLの場合はAutoCommitがデフォルトでONであり、トランザクションを開始する場合は専用のbeginメソッドを利用する。

     # DBI
     $DB->do(q{BEGIN WORK});
     $DB->commit;
     # TL
     $DB->begin;    # $DB->execute(q{BEGIN WORK}) としてはならない
     $DB->commit;

## 拡張プレースホルダ詳細

"execute" に渡されるSQL文には、通常のプレースホルダの他に、 拡張プレースホルダ "??" を埋め込む事が出来る。 拡張プレースホルダの置かれた場所には、パラメータとして通常のスカラー値でなく、 配列へのリファレンスを与えなければならない。配列が複数の値を持っている場合には、 それらが通常のプレースホルダをカンマで繋げたものに展開される。

例: 以下の二文は等価

      $DB->execute(
          q{SELECT * FROM a WHERE a IN (??) AND b = ?},
          ['AAA', 'BBB', 'CCC'], 800);
      $DB->execute(
          q{SELECT * FROM a WHERE a IN (?, ?, ?) AND b = ?},
          'AAA', 'BBB', 'CCC', 800);

パラメータとしての配列の最後の項目が文字列へのリファレンスである時、その文字列は SQL型名として扱われる。配列が複数の値を持つ時には、その全ての要素に対して 型指定が適用される。型名はDBI.pmで定義される。

例:

      $DB->execute(q{SELECT * FROM a LIMIT ??}, [20, \'SQL_INTEGER']);
      ==> SELECT * FROM a LIMIT 20

      $DB->execute(q{SELECT * FROM a LIMIT ??}, [20, 5, \'SQL_INTEGER']);
      ==> SELECT * FROM a LIMIT 20, 5

配列内の要素を更に2要素の配列とし、二番目の要素を文字列へのリファレンスと する事で、要素の型を個別に指定出来る。

例:

      $DB->execute(
          q{SELECT * FROM a WHERE a IN (??) AND b = ?},
          [[100, \'SQL_INTEGER'], 'foo', \'SQL_VARCHAR'], 800);
      ==> SELECT * FROM a WHERE a IN (100, 'foo') AND b = '800'

## METHODS

### `Tripletail::DB` メソッド

`$TL->getDB`

         $DB = $TL->getDB
         $DB = $TL->getDB($inigroup)

  Tripletail::DB オブジェクトを取得。 引数にはIniで設定したグループ名を渡す。 引数省略時は 'DB' グループが使用される。

  $TL->startCgi / $TL->trapError の関数内でDBオブジェクトを取得する場合に使用する。

`$TL->newDB`

         $DB = $TL->newDB
         $DB = $TL->newDB($inigroup)

  新しく Tripletail::DB オブジェクト作成。 引数にはIniで設定したグループ名を渡す。 引数省略時は 'DB' グループが使用される。

  動的にコネクションを作成したい場合などに使用する。 この方法で Tripletail::DB オブジェクトを取得した場合、"connect" / "disconnect" を呼び出し、接続の制御を行う必要がある。

`connect`

  DBに接続する。

  $TL->startCgi / $TL->trapError の関数内でDBオブジェクトを取得する場合には自動的に接続が管理されるため、このメソッドを呼び出してはならない。

  $TL->newDB で作成した Tripletail::DB オブジェクトに関しては、このメソッドを呼び出し、DBへ接続する必要がある。

  connect時には、AutoCommit 及び RaiseError オプションは 1 が指定され、PrintError オプションは 0 が指定される。

`disconnect`

  DBから切断する。

  $TL->startCgi / $TL->trapError の関数内でDBオブジェクトを取得する場合には自動的に接続が管理されるため、このメソッドを呼び出してはならない。

  $TL->newDB で作成した Tripletail::DB オブジェクトに関しては、このメソッドを呼び出し、DBへの接続を切断する必要がある。

`begin`

        $DB->begin
        $DB->begin('SET_W_Trans')

  指定されたDBセット名でトランザクションを開始する。トランザクション名 (DBセット名) はiniで定義されていなければならない。 名前を省略した場合は、デフォルトのDBセットが使われるが、 setDefaultSetによってデフォルトが選ばれていない場合にはエラーとなる。

  CGIの中でトランザクションを開始し、終了せずにMain関数を抜けた場合は、自動的に rollbackされる。

  トランザクション実行中にこのメソッドを呼んだ場合には、エラーとなる。 1度に開始出来るトランザクションは、1つのDBグループにつき1つだけとなる。

`rollback`

        $DB->rollback

  現在実行中のトランザクションを取り消す。

`commit`

        $DB->commit

  現在実行中のトランザクションを確定する。

`setDefaultSet`

        $DB->setDefaultSet('SET_W_Trans')

  デフォルトのDBセットを選択する。ここで設定されたDBセットは、引数無しのbegin() や、beginせずに行ったexecuteの際に使われる。このメソッドは Main関数 の先頭で呼ばれる事を想定している。

`execute`

        $DB->execute($sql, $param...)
        $DB->execute(\'SET_W_Trans' => $sql, $param...)

  SELECT/UPDATE/DELETEなどのSQL文を実行する。 第1引数にSQL、第2引数以降にプレースホルダの引数を渡す。 ただし、第1引数にリファレンスでDBセットを渡すことにより、 トランザクション外での実行時にDBセットを指定することが可能。

  第2引数以降の引数では、拡張プレースホルダが使用できる。 "拡張プレースホルダ詳細" を参照。

  既にトランザクションが実行されていれば、そのトランザクションの DBセットでSQLが実行される。

  トランザクションが開始されておらず、かつ "lock" により テーブルがロックされていれば、ロックをかけているDBセットでSQLが実行される。

  いずれの場合でもない場合は、"setDefaultSet" で指定された トランザクションが使用される。 "setDefaultSet" による設定がされていない場合は、エラーとなる。

  このメソッドを使用して、LOCK/UNLOCK/BEGIN/COMMITといったSQL文を 実行してはならない。実行しようとした場合はエラーになる。 代わりに専用のメソッドを使用する事。

`selectAllHash`

        $DB->selectAllHash($sql, $param...)
        $DB->selectAllHash(\'SET_W_Trans' => $sql, $param...)

  SELECT結果をハッシュの配列へのリファレンスで返す。 データがない場合は [] が返る。

        my $arrayofhash = $DB->selectAllHash($sql, $param...);
        foreach my $hash (@$arrayofhash){
           $TL->log(DBDATA => "name of id $hash->{id} is $hash->{name}");
        }

`selectAllArray`

        $DB->selectAllArray($sql, $param...)
        $DB->selectAllArray(\'SET_W_Trans' => $sql, $param...)

  SELECT結果を配列の配列へのリファレンスで返す。 データがない場合は [] が返る。

        my $arrayofarray = $DB->selectAllArray($sql, $param...);
        foreach my $array (@$arrayofarray){
           $TL->log(DBDATA => $array->[0]);
        }

`selectRowHash`

        $DB->selectRowHash($sql, $param...)
        $DB->selectRowHash(\'SET_W_Trans' => $sql, $param...)

  SELECT結果の最初の１行をハッシュへのリファレンスで返す。 実行後、内部でfinishする。 データがない場合は undef が返る。

        my $hash = $DB->selectRowHash($sql, $param...);
        $TL->log(DBDATA => "name of id $hash->{id} is $hash->{name}");

`selectRowArray`

        $DB->selectRowArray($sql, $param...)
        $DB->selectRowArray(\'SET_W_Trans' => $sql, $param...)

  SELECT結果の最初の１行を配列へのリファレンスで返す。 実行後、内部でfinishする。 データがない場合は undef が返る。

        my $array = $DB->selectRowArray($sql, $param...);
        $TL->log(DBDATA => $array->[0]);

`lock`

        $DB->lock(set => 'SET_W_Trans', read => ['A', 'B'], write => 'C')

  指定されたDBセットに対してLOCK TABLESを実行する。setが省略された場合はデフォルト のDBセットが選ばれる。CGIの中でロックした場合は、 Main関数 を抜けた時点で自動的にunlockされる。

  ロック実行中にこのメソッドを呼んだ場合には、エラーとなる。 1度に開始出来るロックは、1つのDBグループにつき1つだけとなる。

`unlock`

        $DB->unlock

  UNLOCK TABLES を実行する。 ロックがかかっていない場合はエラーとなる。

`setBufferSize`

        $DB->setBufferSize($kbytes)

  バッファサイズをKB単位でセットする。行を１行読み込んだ結果 このサイズを上回る場合、`die`する。 `0` または `undef` をセットすると、制限が解除される。

`symquote`

        $DB->symquote($sym)

  文字列を識別子としてクォートする。

  mysqlの場合は ``a b c`` となり、それ以外の場合は `"a b c"` となる。

getType

        $DB->getType;

  DBのタイプを返す。`(mysql, pgsql, ...)`

getDbh

        $dbh = $DB->getDbh
        $dbh = $DB->getDbh('SET_W_Trans')

  DBセット内のDBハンドルを返す。 返されるオブジェクトは DBI ネイティブのdbhである。

  ネイティブのDBハンドルを使用してクエリを発行した場合、デバッグ機能（プロファイリング等）の機能は使用できません。 また、トランザクションやロック状態の管理もフレームワークで行えなくなるため、注意して使用する必要があります。

### `Tripletail::DB::STH` メソッド

`fetchHash`

        $sth->fetchHash

  ハッシュへのリファレンスで１行取り出す。

`fetchArray`

        $sth->fetchArray

  配列へのリファレンスで１行取り出す。

`ret`

        $sth->ret

  最後に実行した execute の戻り値を返す。

`rows`

        $sth->rows

  DBIと同様。

`finish`

        $sth->finish

  DBIと同様。

`nameArray`

        $sth->nameArray

  `$sth->{NAME_lc}` を返す。

`nameHash`

        $sth->nameHash

  `$sth->{NAME_lc_hash}` を返す。

## Ini パラメータ

### DBセット・DBコネクション

DBグループのパラメータのうち、半角小文字英数字のみで構成された パラメータは予約済みで、DBグループの動作設定に使用する。 DBセットは、予約済みではない名前であれば任意の名称が使用でき、 値としてDBコネクションのINIグループ名をカンマ区切りで指定する。

例:

      [DB]
      namequery=1
      type=mysql
      defaultset=SET_R_Trans
      SET_W_Trans=CON_DBW1
      SET_R_Trans=CON_DBR1,CON_DBR2

      [CON_DBW1]
      dbname=test
      user=daemon
      host=192.168.0.100

      [CON_DBR1]
      dbname=test
      user=daemon
      host=192.168.0.110

      [CON_DBR2]
      dbname=test
      user=daemon
      host=192.168.0.111

以下は特別なパラメータ:

`namequery`

        namequery = 1

  これを1にすると、実行しようとしたクエリのコマンド名の直後に `/* foo.pl:111 [DB.R_Transaction1.DBR1] */` のようなコメントを挿入する。 デフォルトは0。

`type`

        type = mysql

  DBの種類を選択する。 mysql, pgsql, oracleが使用可能。 必須項目。

`defaultset`

        defaultset = SET_W_Trans

  デフォルトのDBセットを設定する。 ここで設定されたDBセットは、引数無しのbegin()や、beginせずに行ったexecuteの際に使われる。

### DB定義

`dbname`

        dbname = test

  DB名を設定する。

`host`

        host = localhost

  DBのアドレスを設定する。 デフォルトはlocalhost。

`user`

        user = www

  DBに接続する際のユーザー名を設定する。

`password`

        password = PASS

  DBに接続する際のパスワードを設定する。 省略可能。

# SEE ALSO

Tripletail

# AUTHOR INFORMATION

Copyright 2006 YMIRLINK Inc. All Rights Reserved.

This framework is free software; you can redistribute it and/or modify it under the same terms as Perl itself

このフレームワークはフリーソフトウェアです。あなたは Perl と同じライセンスの 元で再配布及び変更を行うことが出来ます。

Address bug reports and comments to: tl@tripletail.jp

HP : http://tripletail.jp/

Tripletail::DB - DBIのラッパ

# INDEX

- $TL->getDB
- $TL->newDB
- AUTHOR INFORMATION
- DBIからの移行
- DBグループ・DBセット・DBコネクション
- DBセット・DBコネクション
- DB定義
- DESCRIPTION
- Ini パラメータ
- METHODS
- NAME
- SEE ALSO
- SYNOPSIS
- Tripletail::DB メソッド
- Tripletail::DB::STH メソッド
- begin
- commit
- connect
- dbname
- defaultset
- disconnect
- execute
- fetchArray
- fetchHash
- finish
- getDbh
- getType
- host
- lock
- nameArray
- nameHash
- namequery
- password
- prepare/executeを分けない。fetchは分ける。
- ret
- rollback
- rows
- selectAllArray
- selectAllHash
- selectRowArray
- selectRowHash
- setBufferSize
- setDefaultSet
- symquote
- type
- unlock
- user
- プレースホルダの値渡しの際に型指定が可能
- ラッパに同等の機能が用意されていない場合。
- リクエスト処理完了後のトランザクション未完了やunlock未完了を自動検出
- 実行クエリの処理時間・実行計画・結果を記録するデバッグモード。
- 拡張プレースホルダ機能
- 拡張プレースホルダ詳細
- 接続/切断は自動で行われる。
- 高速な処理が必要で、ラッパのオーバヘッドを回避したい場合。

Tripletail::DB - DBIのラッパ