在我的网站上,我们连接到多个数据库,我们有一个数据库处理类,用于将句柄存储在静态数组中。 99.9%的时间,一切似乎都运行正常,但是偶尔会无声地失败,没有错误,也没有返回任何结果。我已经能够重新创建错误,然后使用以下语法重新创建连接:
$db = new PDO("dblib:host=" . DB_HOST . ";dbname=" . DB_DEFAULT, DB_USER, DB_PASS);
然后,它正确返回结果。但是,我宁愿为所有数据库使用相同的句柄,以保留与创建与数据库的新连接相关的额外开销......或者,至少重新创建连接的次数最少。
无论如何都要评估PDO对象以找出它失败的原因,所以我希望能够弄清楚它是怎么回事?
修改 我已经进一步研究了这个问题,并在发生此错误时对数据库进行了分析。 PDO在遇到某些查询后停止将查询传递给服务器。 (在这种情况下,它是一个插入查询,用于测试记录是否已经存在,如果它没有,那么它会插入它。)
毫无疑问,这对我的问题来说是一个可怕且无法解决的问题,但我复制并粘贴(并通用化了)解决它的问题。基本上,当没有结果返回时,我选择“foo”#39;从数据库中,如果它返回没有结果,我重建连接并尝试再次执行查询。我不接受这个作为答案,因为它非常糟糕。但是这段代码应该更好地说明我试图解决的问题。
/**
* Executes a line of sql with PDO.
*
* @param string $sql
* @param array $params
* @param bool
* @return array
*/
function execute($sql, $params = array(), $retry = false) {
//this call gets the database handle that is stored in a static array, so we can reuse the same connection
$db = db::getDB($this->_database);
if (get_class($db) != 'PDO') {
error('database handle wasn\'t created succesfully...');
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$query = $db->prepare($sql);
$query->execute($params);
} catch (Exception $ex) {
var_dump($ex);
return false;
}
$results = $query->fetchALL(PDO::FETCH_ASSOC);
if(($retry == false) && (!$results)){
$newResults = $this->testAndFixResultsIfDBGoneAway($sql, $params);
if($newResults != false){
$results = $newResults;
}
}
return $results;
}
function isConnected(){
$db = db::getDB($this->_database);
$query = $db->prepare("SELECT 'foo' AS test");
$query->execute();
$results = $query->fetchAll(PDO::FETCH_ASSOC);
//we aren't connected if we get no response
if($results == array()){
return false;
}
//if there is a response, return true
return true;
}
function testAndFixResultsIfDBGoneAway($sql, $params){
if($this->isConnected()){
return false;
}
//recreates the db connection in the db connection class
db::connect($this->_database);
$results = $this->execute($sql, $params, true);
return $results;
}
我注意到我的连接消失了,我可以成功重启,然后下一个查询可能会失败,我可以多次重复这个过程,直到有问题的查询完成,然后一切都开始正常工作,再次。
我真的想知道查询是如何杀死我的数据库连接的,所以我可以阻止它发生,所以我不必在每次都没有返回结果的查询后进行检查。
答案 0 :(得分:0)
设置PDO错误处理模式以使用异常应该使原因立即明显,这样您就不必四处寻找并使用大量调试代码。
$db = new PDO("dblib:host=" . DB_HOST . ";dbname=" . DB_DEFAULT, DB_USER, DB_PASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
但是,您必须更新错误处理代码[准备失败,查询失败]以了解异常。