0
package My::Module;

# $Id$

use strict;
use Carp;
use Data::Dumper;
use DBI;

$My::Module::VERSION  = '0.1';

sub new {
    my ($class, %opt) = @_;
    my $opt_count = keys %opt;

    $class->set_error('');
    #return $class->set_error("Too many arguments to initialize.") if ($opt_count > 5);
    #return $class->set_error("Missing arguments to initialize.") if ($opt_count < 2);

    my $self = bless {
                      _DRIVER_OPTIONS  => $opt{'mysql'},
                     },$class;

    if (not defined $self) {
        return $class->set_error( "new() failed: " . $class->errstr );
    }

    if ($self->{_DRIVER_OPTIONS}->{Host} ne '') {
        $self->{_DRIVER_OPTIONS}->{DataSource} = 'DBI:mysql:database=' . $self->{_DRIVER_OPTIONS}->{Database} . ';host=' . $self->{_DRIVER_OPTIONS}->{Host};
    } else {
        $self->{_DRIVER_OPTIONS}->{DataSource} = 'DBI:mysql:database=' . $self->{_DRIVER_OPTIONS}->{Database} . ';';
    }
    $self->{Handle} = DBI->connect($self->{_DRIVER_OPTIONS}->{DataSource},
                                   $self->{_DRIVER_OPTIONS}->{Username},
                                   $self->{_DRIVER_OPTIONS}->{Password},
                                   { RaiseError=>1, PrintError=>1, AutoCommit=>1 }
                                  );
    return $self->set_error("new(): couldn't connect to database: " . DBI->errstr) unless ($self->{Handle});
    $self->{_disconnect} = 1;

    print Dumper \$self;

    return $self;
}

sub database {
    my $self = shift;
    if (@_) { $self->{Handle} = shift }
    return $self->{Handle};
}

sub set_error {
    my $class   = shift;
    my $message = shift;
    $class = ref($class) || $class;
    no strict 'refs';
    ${ "$class\::errstr" } = sprintf($message || "", @_);
    return;
}

*error = \&errstr;
sub errstr {
    my $class = shift;
    $class = ref( $class ) || $class;

    no strict 'refs';
    return ${ "$class\::errstr" } || '';
}

sub DESTROY {
    my $self = shift;

    unless (defined $self->{Handle} && $self->{Handle}->ping) {
        $self->set_error(__PACKAGE__ . '::DESTROY(). Database handle has gone away');
        return;
    }

    unless ($self->{Handle}->{AutoCommit}) {
        $self->{Handle}->commit;
    }

    if ($self->{_disconnect}) {
        $self->{Handle}->disconnect;
    }
}

1;
  1. 新しい接続を開く代わりにコードでデータベースを再利用できるようにするのは正しい方法ですか、それとも使用するたびに新しい接続を開きますか?

  2. モジュールで何か変更する必要がありますか? または私が間違ったことはありますか?

現在、私は自分のエンジンモジュールを学んで考えているので、これから始めました。

簡単なテスト コード (次のコードは、モジュールの使用方法の単なるサンプルであり、確認する必要はありません):

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
use lib 'path to module';
use My::Module;

my $session = My::Module->new(mysql     => {
                                            Database =>'module',
                                            Host     =>'10.0.0.2',
                                            Username =>'module',
                                            Password =>'module'
                                           }) or die My::Module->errstr;

my $dbh = $session->database();
my $sth = $dbh->prepare(q{
             SELECT session_id
             FROM sessions
          });
   $sth->execute() || die print($dbh->errstr);
my $ref = $sth->fetchall_arrayref({});
$sth->finish;

print Dumper \$ref;
4

3 に答える 3

3

他の人があなたのために理解して解決するのに何年も費やしてきた多くの秘密の落とし穴があるので、私はあなた自身を転がすのではなく、既存のデータベースインターフェースを使用することをお勧めします。 DBIx :: Connectorは優れており、そのfixupモードを使用すると、プロセスフォーク間でもデータベース接続を再利用できます。

さらに、Mooseを使用する場合は、独自のオブジェクトコンストラクターやオブジェクトフィールドを再度作成する必要はありません。:)

DBIx :: ClassをMooseと組み合わせるとさらに優れたものになりますが、ORM風の機能がさらに必要になるまでは必要ありません。

于 2010-10-05T23:13:35.997 に答える
2

このタスクを実行するためにCPANモジュールを使用する以外に、ここに私の実用的な推奨事項があります。

  1. コンストラクターからエラー値を返さないでください。代わりに、例外をスローします。
  2. 直接ハッシュアクセスを使用するのではなく、アクセサーを使用してクラスの内部にアクセスします。
  3. クラスのユーザーが有効にしなかった場合AutoCommit、彼女はAutoCommit理由で有効にしないことを選択しました。したがって、次のことは行わないでください。

    unless ($self->{Handle}->{AutoCommit}) {
        $self->{Handle}->commit;
    }
    

    DESTROY

  4. 変更可能な参照が与えられている限り、blessは失敗しないことに注意してください(たとえば、toの引数が有効なファイル名である場合openでも、ファイルを開くことができない動作と比較して、open偽の値)。したがって、の戻り値をチェックしてblessも、有用な目的はありません。bless失敗の可能性を処理したい場合は、致命的なランタイム例外をキャッチする必要があります。
于 2010-10-05T23:15:25.267 に答える
1

エラーを公開する方法は非常時代遅れです。何か例外が発生した場合、適切な例外を発生させませんか? DBIモジュールの後にエラー処理をモデル化したようです。オプションDBIもあることに注意してください。それを使用することは、ほとんどの場合、旧式のバージョンRaiseErrorを使用するよりも合理的です。errorstr残念ながら、DBI は現在デフォルトを変更することはできませんが、新しいコードでは、この欠陥のあるアイデアをコピーする理由がまったくわかりません。

また、ユーザーが外部から提供したパラメーターに基づいて、コード内で DBI 接続を構築しています。そうする正当な理由はありますか?ユーザーが自分で作成した を渡すことを許可するDBI::dhと、より柔軟になります。はい、オブジェクトをセットアップしてそれらを接続するために外側に少し多くのコードが必要ですが、よりクリーンなデザインにもなります。オブジェクトを手動で配線するのが煩わしい場合Bread::Boardは、モジュールの設計に妥協するのではなく、 を参照して配線を行うことをお勧めします。

また、私は を使用するという Ether の提案を支持しDBIx::Connectorます。非常にエラーが発生しやすいデータベース ハンドルを管理するのは非常に手間がかかります。

于 2010-10-05T23:40:28.973 に答える