読者です 読者をやめる 読者になる 読者になる

とあるプログラマの備忘録

都内某所に住むプログラマが自分用に備忘録を残すという趣旨のブログです。はてなダイアリーから移動しました!

DBエラー発生時の一括処理

本当は私PHP畑の人間なんですが、、
最近全然違う言語とかインフラやってます。

「悲しいけどこれって仕事なのよね。」
「坊やだからさ」

うるさいこのガ○ダム!

独り言はこれくらいにして、今回の例は「DBエラー発生時の一括処理を書いてみた」
です。

実際、今回が初めてperlを触っているので、
perlの罠にはまりっぱなしですが、ちょっと作ってみたので覚書。

※ソースの動確してません。間違いがあったらお知らせください。


前提条件
・必要なモジュールはすでにCPANから落としてきていること
  CPAN -> http://search.cpan.org/

use DBI;

#require
require 'pram.pl';

# 変数定義
my $dbh;

#DBconnect
$dbh = DBI->connect("dbi:Oracle:host=$HOST;sid=$SID", $USER, $PWD,
{RaiseError => 1, PrintError => 0, AutoCommit => 0 });

if($dbh == undef ) {
    print "コネクトに失敗しました。処理を終了します。";
    exit;
}

#主制御
&main();

#メインメソッド
sub main{
  
  #SQL作成
  my $sql = "SELECT * FROM TESTTBL";
  
  #エラーヘッダー作成
  $sqlMsg = "【SELECT ERROR】";
  #実行メソッドに送る
  &query($sql,$sqlMsg);

  #SQL作成
  my $sql2 = "INSERT INTO TESTTBL VALUES('hoge','hogehoge')";
  
  #エラーヘッダー作成
  $sql2msg = "【INSERT ERROR】";
  #実行メソッドに送る
  &query($sql2,$sql2msg);
}

#実行メソッド
sub query{

  #引数取得
  $sql = $_[0];
  $msg = $_[1];

  eval{

    $nres =$dbh->prepare($sql);
    #実行
    $nres->execute();

    #ここまできたらコミット
    $dbh->commit;
  };
  if ( $@ ){

    #ロールバック
    $dbh->rollback;

    #エラー出力
    print $msg.$dbh->errstr;

    #処理を続行したい場合は外す
    exit;
  }
}

抜粋して書くとさっぱりしますね。
軽く説明

require 'pram.pl';

ここにDB情報が入ってます。

$dbh = DBI->connect("dbi:Oracle:host=$HOST;sid=$SID", $USER, $PWD,
           {RaiseError => 1, PrintError => 0, AutoCommit => 0 });

DBのコネクトとともに、AutoCommitをOFFにします。0にすることでコミットとロールバックのタイミングを
こちらで指定してやる必要があります。
また、PrintErrorも0にしたのは重複でエラーが出てしまうので、それを防ぐために0にしています。

コネクトに失敗したらそこで処理終了。

#クエリ作成
    my $sql = "SELECT * FROM TESTTBL";

ここでprepareしてしまうと、
もしもエラー発生時の対処が必要な場合、
SQLごとにその処理を書かなくてならないので、
ここでは文字列として変数に渡します。

#エラーヘッダー作成
$sqlMsg = "【SELECT ERROR】";
#実行メソッドに送る
&query($sql,$sqlMsg);

ヘッダーを作成して、SQLと一緒にメソッドへ送る。

eval{

    $nres =$dbh->prepare($sql);
    #実行
    $nres->execute();

    #ここまできたらコミット
    $dbh->commit;
};

引数を取得したら、ここでprepare
evalで囲むことによってtry~cachの役割を果たしくれます。
エラーが発生しなかった場合はそのままコミット。

  if ( $@ ){

    #ロールバック
    $dbh->rollback;

    #エラー出力
    print $msg.$dbh->errstr;

    exit;
  }

エラーが発生した場合はこちらに流れてくるので、
ロールバック処理。

先ほど作成したエラーヘッダーとあわせて、ORACLE
エラーを出力。


******************************
こんな感じにすれば毎回prepareした時にエラー出力処理を書かなくてもいいはずです。
多少ソースが綺麗に見えるかな?

それと、今回は書いていませんが、
ロールバック>エラーをログに出力>処理続行
なんて処理を書きたい場合もあるでしょう。

そんな時はif( $@ )内にあるexitを外して、
エラー出力の場所に証跡ログを出力するメソッドを追加してやればOKです。


この記事を参考に実装した際の損害、障害は一切責任を負いかねます。
実装時は自己責任でお願いします。