【发布时间】:2018-02-09 00:16:23
【问题描述】:
我需要拦截所有查询(例如,为了进行一些结构化日志记录)。
该应用程序已经使用子类 DBI,所以我希望我可以将我需要的代码注入到 MyDB::st 类中的 execute 重载中。
显然,这还不够。
在下面的示例中,MyDB::st::execute 仅在示例 2) 中执行。它不会在 1) 我调用 do 的地方执行,也不会在 3) 我调用 selectrow_array 的地方执行(即使文档说 selectrow_array 结合了 prepare、execute 和 fetchrow_hashref)。
我是否也需要重载 MyDB::db 类中的语句?有很多(do、selectrow_array、selectrow_arrayref、selectrow_hashref、selectall_arrayref、selectall_array、selectall_hashref、selectcol_arrayref 等)我希望我能避免这种情况。
为了简单起见,该示例使用 SQLite,但我检查的其他驱动程序的工作方式相同。
#!/usr/bin/perl
package MyDB;
use strict;
use warnings;
use base 'DBI';
sub connect {
return DBI::connect( 'MyDB', 'dbi:SQLite:dbname=so.sqlite', '', '',);
}
package MyDB::db;
use strict;
use warnings;
use base 'DBI::db';
sub prepare {
my $self = shift;
warn " DB: PREPARE\n";
return $self->SUPER::prepare( @_ );
}
package MyDB::st;
use strict;
use warnings;
use base 'DBI::st';
sub execute {
my $self = shift;
warn " ST: EXECUTE\n";
return $self->SUPER::execute( @_ );
}
sub fetchrow_hashref {
my $self = shift;
warn " ST: FETCHROW_HASHREF\n";
return $self->SUPER::fetchrow_hashref( @_ );
}
package main;
use strict;
use warnings;
my $dbh = MyDB::connect();
warn "1) --- DO ---\n";
$dbh->do("CREATE TABLE IF NOT EXISTS ttt (a int)");
warn "2) --- PREPARE/EXECUTE/FETCHROW_HASHREF ---\n";
my $sth = $dbh->prepare( "SELECT * FROM ttt" );
$sth->execute();
$sth->fetchrow_hashref();
warn "3) --- SELECTROW_ARRAY ---\n";
$dbh->selectrow_array( "SELECT * FROM ttt" );
【问题讨论】:
-
最好准确地说出您打算做什么,因为(例如)DBD::SQlite 已经具备记录语句的能力,因此没有理由拦截查询。 IIRC 类似于
$dbh->sqlite_trace=1; -
DBI对包做了一些奇怪的事情。我更希望看到您需要挂钩的操作的简单包装器,而不是尝试覆盖继承的方法。 -
@ChrisTurner - 我需要以结构化方式转储一些数据(查询、执行时间、有关程序状态的一些信息)。