Perl Hackers Hub

第3回 DBIx::Classでデータベース操作(2)

この記事を読むのに必要な時間:およそ 3 分

Schema::Loaderの利用

第3回(1)でResultクラスには各テーブルがどのようなカラムを持っているかを定義する必要があると書きましたが,⁠そのようなテーブル情報はデータベースから自動的に取得できるのでは?」と思った方もいるかもしれません。DBIx::Class::Schema::Loaderという別で配布されているモジュールを使用すると,Resultクラスでのテーブル情報の定義を省略できます。

Schema::Loaderを使うべきか

軽いデータベース操作であればSchema::Loaderがお手軽ですが,そうではない場合はResultクラスにテーブル定義をしっかりと書くのがお勧めです。Resultクラスにテーブル定義を書くべき理由は主に2つあります。

●DBIx::Classからデータベースを作成できる

Resultクラスにテーブル定義を書くと,DBIx::Classからデータベースを作成できます。しっかりテーブル定義が書かれている場合,

my $schema =
    My::Schema->connect('dbi:SQLite:/path/to/my.db');
$schema->deploy;

とdeployメソッドを使用してデータベースを作成できます。これは特定のデータベース実装に依存しないようにできていますので,上記の例ではSQLiteデータベースを作成していますし,次のようにすれば同じ定義からMy SQLに対してテーブルを作成することもできます。

my $schema = My::Schema->connect(
    'dbi:mysql:mydb', 'mysql_user', 'mysql_password',
);
$schema->deploy;

これで,Resultクラスに書かれているテーブル定義に沿ってCREATE TABLEが実行され,テーブルが作成されます。なお,My SQLの場合はあらかじめデータベースは作成しておく必要があります。

●Schemaバージョニング機能が利用できる

Resultクラスにテーブル定義を書くと,Schemaバージョニングというさらに便利な機能も利用できます。

開発を進めていくにつれ,もしくはアプリケーションのバージョンアップ時など,データベース定義を変更することがあると思います。このような場合にdeployメソッドは役に立たないでしょう。そのたびにテーブルを作りなおすわけにはいきません。

Schemaバージョニングは,DBIx::Classでのデータベース定義と実際のデータベース定義との差分を判別して適切なALTER TABLEを発行してくれたり,バージョンが一致しないデータベースに接続しようとすると警告を発してくれたりする便利な機能です。

この機能の詳細はDBIx::Class::Schema::Versionedにまとまっていますので参照してください。

ページャオブジェクト

データベースから取得するデータが多い場合には,LIMIT句などを使用してデータサイズを指定したページング処理を使うことが多いと思います。

DBIx::Classのsearchメソッドには検索結果と連動したページャオブジェクトを取得できる機能があります。ページャオブジェクトを使用するとWebサイトなどでよく使用するページネーション表示などを簡単に作成できます。

ページャオブジェクトを使用するにはsearchメソッドにrows属性とpage属性を渡します。

my $rs = $schema->resultset('Tweets')->search(
    {}, { rows => 10, page => 1, }
);

rows属性には1ページあたりの表示件数を,page属性には何ページめを表示するかをそれぞれ渡します。すると返されたResultSetオブジェクトのpagerメソッドで,それに対応するページャオブジェクトを取得できます。

my $pager = $rs->pager;

このページャオブジェクトはData::Pageのオブジェクトになっています。

トランザクション

トランザクションをサポートするRDBMSを使用している場合にはDBIx::Classはトランザクションをサポートします。現在DBIx::Classからトランザクションを扱うには次の3つの方法があります。

  • txn_do
  • txn_scope_guard
  • txn_begin/txn_commit/txn_rollback

これらはすべてSchemaオブジェクトのメソッドです。

txn_doを使ったトランザクション

DBIx::Classにおける一番確実なトランザクションの方法は,txn_doメソッドを使用することです。

use Try::Tiny;

my $res;
try {
    $res = $schema->txn_do(sub {
        # トランザクション処理したい一連の処理
    });
} catch {
    if ($_ =~ /Rollback failed/) {
        # ロールバックに失敗した場合
    }

    # 何らかのエラーによりロールバックした
}

txn_doにはトランザクションしたい処理をコードリファレンスにして渡します。txn_doはまずトランザクションを開始しその中でコードリファレンスを実行します。そしてその中で何らかのエラーが発生すると自動的にrollbackを発行してくれます。コードリファレンス内で起きた例外はrethrowされるので,それをキャッチするためにはevalでくくるかこの例のようにTry::Tinyなどを使用してあげる必要があります。

txn_doを使用する注意点として,コードリファレンス内にはデータベースを扱う処理以外も書くことができますが,もちろんそれらはデータベースのロールバックが呼ばれても元に戻ることはありません。また,処理中にデータベースの接続が切れた場合,DBIx::Classは自動的に初めから処理をやりなおします。そのときにはデータベースに関係のないコードは2回実行されてしまうことになります。データベース操作以外のコードをコードリファレンスに含める場合は,意図せずコードが実行されてしまう可能性があることに注意してください。

著者プロフィール

村瀬大輔(むらせだいすけ,ハンドルネーム:typester)

1981年2月生まれ。2004年9月株式会社カヤックに入社。

カヤックでは自社サービス「こえ部」を担当する傍ら,ラボチームBM11に所属し「Ark」「nim」といったオープンソースプロダクトを開発。また「Shibuya.pm」や「YAPC::Asia」にスピーカーとして参加するなど,Perlプログラマとして活躍の場を広げている。

コメント

コメントの記入