支持自动重连接的PHP PDO类完善

发布: 2013-03-09 18:28

PHP的PDO是取代原来的php-mysql、php-mysqli模块的统一数据库访问模块,

比直接使用各自数据库提供的原始扩展函数相比,PDO的好处是移植性更好些。

最近在使用PDO开发框架过程,对其有了更多些的认识。

*)对长连接的支持

*)异常的使用

*)连接的自动关闭控制

*)连接中断的重连接(MySQL has gone away)

*)

最近遇到特别麻烦的问题,使用长连接是,全出来 MySQL Server has gone away的问题。

这种情况下PDO没有办法检测并重连接,也没有提供重新连接的相关方法。

这样对长连接的使用有点悲催了,开始运行的很正常的系统,运行一段时间后,却因为数据库连接的问题系统瘫痪了。

经过很多的代码测试与查找资料,实现了一个能重连接的PDO封装。在此分享思路与主要代码,补充PDO在实际应用中遇到的问题。

该封装的主要思路:
使用PDO的异常模式设置,
通过PHP魔法方法__call($name, $args)代理PDO的所有方法,
在代理方法中截获PDO的异常,判断异常的类型,确定是否需要重新连接。
在这一层封装还屏蔽了PDO的异常功能,所有的PDO操作成功与否需要通过调用返回值和errorInfo等方法取得。

这种方法为了实现自动重连功能,实际上降低了代码的效率。
在实际应用中,根据需要确定对效率的需求如何,是否可以接受这种效率损失。

最后,希望能在PDO的核心改进这个问题,或者提供显著重连接的方法,

或者提供显式的关闭当前已经中断连接的方法,

更或者提供一个参数,让PDO确定在遇到这种问题时能够自动重连接,如PDO::AUTO_RECONNECT。

抽时间出看看PDO的代码,看自己能否简单的HACKING下PDO扩展模块,实现我们需要的功能。

附:自动重连接PDO封装类,
[code type="PHP"]

public function __call($name, array $arguments)
{
$result = false;
$cnter = self::REQUERY_TIMES;
do {
try {
$result = call_user_func_array(array($this->connection(), $name), $arguments);
if ($result instanceof PDOStatement) {
$result = new ReconnectingPDOStatement($result);
}
break;
} catch(PDOException $e) {
if($e->getCode() != 'HY000' || !stristr($e->getMessage(), 'server has gone away')) {
throw $e;
}

$this->reconnect();
}
} while($cnter-- > 0);

return $result;
}

protected function connection()
{
return $this->pdo instanceof PDO ? $this->pdo : $this->connect();
}
public function connect()
{
$dsn = $this->dsn.';'.time()%10;
if($this->pdo)
{
//让php先回收已断开长连接资源
$this->pdo->setAttribute(PDO::ATTR_PERSISTENT, false);
$this->pdo = null;
$this->pdo = new PDO($dsn, $this->username, $this->password, (array) $this->driver_options);
$this->pdo->setAttribute(PDO::ATTR_TIMEOUT, 3600);
$this->pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
}
else
{
$this->pdo = new PDO($dsn, $this->username, $this->password, (array) $this->driver_options);
$this->pdo->setAttribute(PDO::ATTR_TIMEOUT, 3600);
}

return $this->pdo;
}

public function reconnect()
{
return $this->connect();
}
}

class ReconnectingPDOStatement
{
private $_stmt = null;

public function __construct($stmt) {
$this->_stmt = $stmt;
}

public function __call($name, array $arguments) {
$result = false;
try {
$result = call_user_func_array(array($this->_stmt, $name), $arguments);
} catch (PDOException $e) {
// var_dump($e);
}
return $result;
}
}
[/code]


原文: http://qtchina.tk/?q=node/719

Powered by zexport