我正在使用Apache2.2(worker)/ mod_perl 2.0.4 / Apache :: DBI / CGI :: Session和Firebird RDBMS。
我还编写了CGI :: Session :: Driver :: firebird.pm来使用Firebird RDBMS。 数据库连接由Apache :: DBI汇集,并为CGI :: Session {Handle => $ dbh}提供连接句柄。
数据库连接数等于工作进程数。
我在3个月前发布了Programming with Apache::DBI and firebird. Get Stucked httpd on exception。 我找到了这个问题的原因,并想知道如何修复它。
$dbh = DBI->connect("dbi:Firebird:db=$DBSERVER:/home/cdbs/xxnet.fdb;
ib_charset=UTF8;ib_dialect=3",$DBUSER,$DBPASS,{
AutoCommit=>1,
LongReadLen=>8192,
RaiseError=>1
});
my $session = new CGI::Session('dbi:firebird',$sessid,{Handle=>$dbh});
my $ses_p1 = $session->param('p1');
eval { $dbh->begin_work()
my $sql = "SELECT * FROM SAMPLETABLE"
my $st = $dbh->prepare($sql);
$st->execute();
while (my $R = $st->fetchrow_hashref()) {
...
}
$st->finish();
}; warn $@ if $@;
if ($@) {
$dbh->rollback();
}else{
$dbh->commit();
}
$session->flush();
当发生sql错误时,eval块会捕获异常和回滚事务。 之后,CGI :: Session不再检索会话对象。
因为prepare_cached语句在CGI :: Session :: DBI.pm处失败。 CGI :: Session :: DBI.pm使用prepare_cached($ sql,undef,3)。 ' 3'是使用缓存语句最安全的方法,但在这种情况下它永远不会找到破坏的语句。
如何解决这个问题? 提出更改CGI :: Session :: DBI.pm的请求以使用prepare()语句? 在firebird.pm中写store(),retrieve(),traverse()函数来使用prepare()语句?
在捕获异常后,其他prepare_cached()可能会失败...
1)我在CGI :: Session-> errstr()上添加了die语句 我收到错误" new():failed:load():无法检索数据:retrieve():$ sth->执行失败并显示错误消息" 2)我在session-> load()之后刷新会话对象 如果$ session有效,则更改将存储到DB。 3)我将begin_work()替换为{AutoCommit} = 0 结果是一样的。我可以在捕获异常和回滚后正常使用$ dbh,但是新的CGI :: Session返回错误。 ------------------------------------------已添加2017/07/26 18: 47 JST
请给我你的建议。
谢谢。
答案 0 :(得分:1)
在请求更改为CGI :: Session :: Driver :: DBI.pm ...
之前,您可以尝试各种各样的事情。首先,更改调用new CGI::Session
的方式,以便在创建或加载会话时诊断问题是否发生:
my $session = CGI::Session->new('dbi:firebird',$sessid,{Handle=>$dbh}) or die CGI::Session->errstr();
方法param
或delete
存储$session
句柄内的会话更改,而不存储在DB中。 flush
在DB中存储会话句柄内所做的更改。仅在会话 - >参数设置/更新或会话删除后使用$session->flush()
:
$session->param('p1','someParamValue');
$session->flush() or die 'Unable to update session storage!';
# OR
$session->delete();
$session->flush() or die 'Unable to update session storage!';
方法flush
不会破坏$session
句柄(您可以在刷新后调用$session->param('p1')
)。在某些情况下,mod_perl会缓存$session
,导致下次尝试加载同一会话时出现问题。在那些情况下,它需要在不再需要时销毁:
undef($session)
我可以建议的最后一件事是避免使用begin_work
方法,而是使用AutoCommit
控制事务行为(因为DBD::Firebird documentation表示应该控制事务的方式)和{{ 1}}在eval块内:
commit
你说你为Firebird编写了自己的会话驱动程序...你应该看看如何制作CGI / Driver / sqlite.pm或CGI / Driver / mysql.pm,也许你需要写一些你缺少的提取方法...
希望这会有所帮助!!