2017-07-18 107 views
2

我使用Apache2.2(worker)/ mod_perl 2.0.4/Apache :: DBI/CGI :: Session和Firebird RDBMS。DBI緩存語句消失,CGI :: Session被阻塞

我還寫了CGI :: Session :: Driver :: firebird.pm來與Firebird RDBMS一起工作。 DB連接由Apache :: DBI彙集,併爲CGI :: Session {Handle => $ dbh}提供連接句柄。

DB連接的數量等於工作進程的數量。

我發佈了Programming with Apache::DBI and firebird. Get Stucked httpd on exception 3個月前。 我發現了這個問題的原因,並想知道如何解決它。

$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 [email protected] if [email protected]; 
if ([email protected]) { 
    $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中使用prepare()語句寫入store(),retrieve(),traverse()函數?

可能其他prepare_cached()去捕獲異常後失敗...


1)我的CGI ::會話級> errstr() 添加模具發言中,我得到了一個錯誤「新的( ):失敗:load():無法檢索data:retrieve():$ sth->執行失敗,顯示錯誤消息「 2)如果$ session有效,則會話 - >加載() 後刷新會話對象,被存儲到數據庫。 3)我將begin_work()替換爲{AutoCommit} = 0 結果相同。在捕獲異常和回滾之後,我可以正常使用$ dbh,但是新的CGI :: Session返回錯誤。 ------------------------------------------ added 2017/07/26 18 :47 JST

請給我你的建議。

謝謝。

+0

''session-> flush'殺死會話?也許有人希望從'$ sessid'中刪除任何值? –

+0

$ session-> flush()不會引發任何異常。 $ session-> flush()之後,另一個查詢運行良好,但下一個「新CGI :: Session()」返回空。 CGI :: Session-> load()返回undef。 –

+0

我也通過刪除$ session-> flush()來測試它,但下一個CGI:Session返回空。 –

回答

2

有,你可以請求更改爲CGI之前嘗試各種東西::會議::驅動程序:: DBI.pm ...

首先,如果問題發生改變new CGI::Session被調用順序的方法來診斷當會話創建或加載:

my $session = CGI::Session->new('dbi:firebird',$sessid,{Handle=>$dbh}) or die CGI::Session->errstr(); 

的方法paramdelete儲存在內部$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手柄(你仍然可以調用flush後$session->param('p1'))的方法。在某些情況下,mod_perl高速緩存$session會導致下次嘗試加載同一會話時出現問題。在這種情況下,它需要的時候不需要的話再被破壞:

undef($session) 

的最後一件事我可以建議是避免使用begin_work方法,控制與AutoCommit而不是交易行爲(因爲DBD::Firebird documentation說,這交易的方式應被控制)和commit的eval塊內:

eval { 
    # Setting AutoCommit to 0 enables transaction behavior 
    $dbh->{AutoCommit} = 0; 

    my $sql = "SELECT * FROM SAMPLETABLE" 
    my $st = $dbh->prepare($sql); 
    $st->execute(); 

    while (my $R = $st->fetchrow_hashref()) { 
     ... 
     } 

    $st->finish(); 
    $dbh->commit(); 
    }; 
if ([email protected]) { 
    warn "Tansaction aborted! [email protected]"; 
    $dbh->rollback(); 
    } 

# Remember to set AutoCommit to 1 after the eval 
$dbh->{AutoCommit} = 1; 

你說你寫你自己的會話驅動程序火鳥...你應該看到的CGI /驅動器/ sqlite.pm或CGI /驅動器/ mysql.pm被製造出來,也許你需要寫一些取材方法y ou失蹤...

希望這有助於!

+0

1)add die CGI :: Session-> errstr(): 2)flush flush():對象: 如果$ session有效,則更改將存儲到數據庫。 3)使用{AutoCommit} = 0和其他: 情況是一樣的。在捕獲異常和回滾之後,我可以正常使用$ dbh,但是新的CGI :: Session返回錯誤。 --- 我的驅動程序/ firebird.pm只有init()和table_name(),然後在DBI.pm中使用store/retrieve。我寫了firebird.pm來加載DBD :: Firebird並將DSN設置爲'dbi:firebird'。 –

+0

我添加商店,檢索,沒有「_cached」遍歷firebird.pm。它看起來工作正常。 mysql.pm有mk_dsn,init,table_name,store。 store()更改爲使用DBI.pm中的'ON DUPLICATES'。 DBI-> begin_work()將{AutoCommit}更改爲0. 我找到了解決方法。所以,我想知道爲什麼緩存語句不見了? –

+0

你能否用你找到的錯誤更新你的問題? – kidkamek