トランザクション
トランザクションは、データベースへの関連する一連の変更が、基本な単位で行われること保証することにより、エラーとデータベース障害から守ります。
このセクションはトランザクションをサポートし、AutoCommitがオフになっている、データベースにあてはまります。各種のデータベースに対するAutoCommitの使い方の詳細についてはAutoCommitを参照してください。
Perlアプリケーションで強力なトランザクションを実現する方法は、RaiseErrorとevel{...}を使うことをお勧めします(これはevel "..."よりとても速く動きます)。
$dbh->{AutoCommit} = 0; # 可能であれば、トランザクションを有効にします
$dbh->{RaiseError} = 1;
eval {
foo(...) # INSERTやUPDATEを含む
bar(...) # 多くの処理を baz(...) # ここでします。
$dbh->commit; # ここまで来たらコミットします。
};
if ($@) {
warn "Transaction aborted because $@";
$dbh->rollback; # undo the incomplete changes
# 他のアプリケーションの後片付けの処理をここに入れます
}
RaiseError属性が設定されていなければ、DBI呼び出しは手動でエラーのチェックをする必要があります。通常は以下のようにします。
$h->method(@args) or die $h->errstr;
RaiseErrorを設定すると、そのハンドルや、その子供のハンドルで呼び出されるDBIメソッドが失敗すると、DBIは自動的に死にます(die) 。そのため各メソッド呼び出しの戻り値をいちいちチェックする必要がなくなります。詳細についてはRaiseErrorを参照してください。
evalによる方法の大きな利点は、アプリケーション内部のいかなる理由で、どのような処理で死んでも(die)、トランザクションが適切にロールバックされることにあります。$h->{RaiseError}属性を使う大きな利点は、すべてのDBI呼び出しが自動的にチェックされることにあります。
commitやrollbackを呼び出した後、多くのドライバは同じデータベース・ハンドルの子供で以前はアクティブだったSELECTステートメント・ハンドルからの取り出しをさせてくれません。これを避ける方法は、データベースに2回接続し、1つの接続をSELECTストートメントのために使うことです。
BLOB/LONG/Memoフィールドの扱い
多くのデータベースは、非常に長い文字列や大量のバイナリデータを一つのフィールドに保持するために、BLOB、longや似たデータ型をサポートします。いくつかのデータベースは、長さ2,000,000,000バイト以上の可変長のlong値をサポートします。
longやバイナリの値を挿入する場合、INSERTステートメントの最大のサイズに制限があったり、quoteメソッドがバイナリデータに対処できないので、プレースホルダを使用してください。詳しくはプレースホルダとバインド値を参照してください。
単純な例
データをSELECTしフェッチする
my $dbh = DBI->connect("dbi:DriverName:db_name", $user,$password)
or die "Can't connect to $data_source:$DBI::errstr";
my $sth = $dbh->prepare( "SELECT name, phone FROM mytelbook")
or die "Can't prepare statement: $DBI::errstr";
my $rc = $sth->execute
or die "Can't execute statement: $DBI::errstr";
print "Query will return $sth->{NUM_OF_FIELDS} fields.\n\n";
print "Field names: @{ $sth->{NAME} }\n";
while (($name, $phone) = $sth->fetchrow_array) {
print "$name: $phone\n";
}
die $sth->errstr if $sth->err;
$dbh->disconnect;
ファイルからあるデータを挿入します(この例は各呼び出しをチェックする必要があることを回避するためにRaiseErrorを使用します) 。
my $dbh = DBI->connect("dbi:DriverName:db_name", $user, $password, {
RaiseError => 1, AutoCommit => 0
});
my $sth = $dbh->prepare( q{
INSERT INTO table (name, phone) VALUES (?, ?)
});
open FH, "<phone.csv" or die "Unable to open phone.csv:$!";
while (<FH>) {
chop;
my ($name, $phone) = split /,/;
$sth->execute($name, $phone);
}
close FH;
$dbh->commit;
$dbh->disconnect;
#フェッチされたNULL(未定義の値)を空の文字列に変換すること:
while($row = $sth->fetchrow_arrayref) {
foreach (@$row) { $_ = '' unless defined }
print "@$row\n";
}
これらの例で使用されているq{}スタイルの引用は、SQLステートメントの中で使用されるかもしれない引用とぶつかることを回避します。文字列に変数を差し挟みたければ、qq{...}演算子のようにダブルクォートを使用してください。
デバッグ
traceメソッドに加えて、Perlを始める前にDBI_TRACE環境変数をセットすることにより、同じトレース情報を有効にすることができます。
UNIXライクのシステムにおいては、シェルを使用して、単一のコマンドでこれを容易に行うことができます。
DBI_TRACE=2 perl your_test_script.pl
DBI_TRACEが数値でない値に設定される場合、ファイル名であると仮定され、トレースレベルを2に設定して、すべてのトレース出力はそのファイルに追加され
ます。
詳細はtraceメソッドを参照してください。