2012-02-08 54 views

回答

1

最好的方法是将PDO实例创建包装成一个存储实例和创建时间的单例(即MyPDOFactory),这样,您可以在达到TTL后重用它或重新创建它(2或3秒对于大多数应用来说已经足够了)。您只需调用MyPDOFactory :: get()即可获得一个可用于准备PDOStatement的有效PDO,只需确保尽快执行即可。

+0

我明白你的想法,但你真的应该添加代码到你的答案。 – 2013-12-03 21:40:52

+0

如果您正在运行一组查询,那么会发生什么情况:a)事务性,以及b)比TTL需要更长的时间? – GordonM 2016-04-05 10:25:43

-1

我认为这可以帮助你。

/* Your Database Name */ 
    $dbname = 'mydatabase'; 

    /* Your Database User Name and Passowrd */ 
    $username = 'root'; 
    $password = 'password'; 

    try { 
     /* Establish the database connection */ 
     $conn = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password); 
     $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    /* your code goes here*/ 
} catch(PDOException $e) { 
     echo 'ERROR: ' . $e->getMessage(); 
    } 
    //mysql_close($conn); 

    $conn=null; 
+0

您的答案在超时后无法重新连接。在try块你应该把查询代码,如果连接不见了,重新连接catch块。然后以某种方式再次启动查询... – 2013-12-13 10:55:55

0

发生错误后重新连接到数据库实际上是一个比看起来更复杂的问题。

我的第一个想法是写PDO一个简单的包装类,代理方式在内部PDO对象,并且可以处理连接错误本身:

class BetterPDO extends PDO 
{ 
    private $realPDO = NULL; 
    private $dsn  = ""; 
    private $username = ""; 
    private $password = ""; 
    private $options = []; 

    public function __construct ($dsn, $username = "", $password = "", $options = []) 
    { 
     $this -> dsn = $dsn; 
     $this -> username = $username; 
     $this -> password = $password; 
     $this -> options = $options; 
    } 

    private function getRealPDO() 
    { 
     if (is_null ($this -> realPDO)) 
     { 
      $this -> realPDO = new PDO ($this -> dsn, $this -> username, $this -> password, $this -> options); 
     } 
     return $this -> realPDO; 
    } 

    // We're only implementing exec for brevity but you have to do this for all public methods of PDO 
    public function exec ($sql) 
    { 
     $retries = 0; 
     while (true) 
     { 
      try 
      { 
       return $this -> getRealPDO() -> exec ($sql); 
      } 
      catch (PDOException $ex) 
      { 
       $this -> realPDO = NULL; 
       if (++$retries > 5) 
       { 
        // We've passed our retry limit 
        throw $ex; 
       } 
      } 
     } 
    } 
} 

由于这一类扩展PDO,它可以在任何地方使用的可以使用通用的PDO类。你可以看到,这种方法会在exec()方法放弃之前给你一些重试,允许在瞬时错误之后重新连接(这仅仅是为了演示,并且缺乏一些真正实现需要的功能,比如重试之间的退避,足够的错误记录等)。这种方法还需要您检查抛出的PDO异常的具体情况,理由是您不希望MySQL语法错误等事件导致连接重置并尝试重试。你只希望它发生在诸如“服务器已经消失”之类的事情上。

正如你所看到的,实现所有代理的PDO方法将会是一件苦差事,尽管你只需要投入努力就可以做到这一点。

虽然有一个更大的问题,这对任何与数据库进行通信的代码来说都是一个普遍问题,而不仅仅是PDO。如果在交易过程中连接丢失会发生什么?在这种情况下,您不希望脚本重新连接并选择停止的位置,因为您完成上一次提交所做的所有工作都将丢失,并且有可能会导致恢复失败重新连接后,你必须重新开始。因此,您可能只希望整个脚本重新开始,尝试重新连接就没有任何意义。这可能是为什么mySQLI支持重新连接,但PDO不支持。

如果您的脚本只读取或非事务性写入,那么上述方法仍然有价值,但只要您将事务处理引入混音中,您实际上会更好,而不会尝试重新连接。