简体   繁体   中英

PDO: Connection timed out when database is offline

I have a website that makes a connection to an external database with PDO.

All right, all works.

The only problem is when the database goes offline. I refresh the website, the browser load the first query that finds but it takes 30+ seconds to load it and when finish the page stop to load (because there is an exit(); function when the connection fails) with this error:

SQLSTATE[HY000] [2002] Connection timed out

I want the website accessible normally when the database goes offline, because is a routine that it goes offline but there's this problem of the Connection timed out and of the page that takes 30+ seconds to load.

How can I resolve this problem?

This is how I do a connection and a query:

class.db.php

<?php
class db
{
    private $db = NULL;
    private $host = NULL;
    private $user = NULL;
    private $password = NULL;
    private $port = NULL;

    public function __construct($host, $user, $password, $port) {
        $this->host = $host;
        $this->user = $user;
        $this->password = $password;
        $this->port = $port;
    }

    private function initDb() {
        if($this->db == NULL) {
            try {
                $this->db = new PDO('mysql:port='.$this->port.';host='.$this->host, $this->user, $this->password);
                $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            }
            catch (PDOException $error) {
                echo '<b>An error occured!</b><br />' . $error->getMessage();
                exit();
            }
        }
    }

    public function query($array) {
        $this->initDb();
        $sql = $array['sql'];
        $par = (isset($array['par'])) ? $array['par'] : array();
        $ret = (isset($array['ret'])) ? $array['ret'] : 'res';
        $obj = $this->db->prepare($sql);
        $result = $obj->execute($par);
        if (!$result) exit("Errore Query");
        switch ($ret) {
            case 'fetch-assoc':
                return $obj->fetch(PDO::FETCH_ASSOC);
            break;

            case 'fetch-all':
                return $obj->fetchAll(PDO::FETCH_ASSOC);
            break;

            case 'fetch-column':
                return $obj->fetchColumn();
            break;

            case 'result':
                return $result;
            break;

            default:
                return $result;
            break;
        }
    }

    public function __destruct() {
        $this->db = NULL;
    }
}

Usage (how I run a query)

require_once ROOT . 'include/class.db.php';

$config['db']['servername'] = ""; // Database IP
$config['db']['username'] = ""; // Database Username
$config['db']['password'] = ""; // Database Password
$config['db']['port'] = 3306; // Database Port

$db = new db($config['db']['servername'], $config['db']['username'], $config['db']['password'], $config['db']['port']);

// Example of a query

$data = $db->query(array(  
    'sql' => "SELECT count(*) FROM player.player WHERE DATE_SUB(NOW(), INTERVAL 1 DAY) < player.last_play",
    'ret' => 'fetch-column'
));

echo $data;

Thanks for the help.

You could set the timeout attribute:

private function initDb() {
    if($this->db == NULL) {
        try {
            $this->db = new PDO('mysql:port='.$this->port.';host='.$this->host, $this->user, $this->password);
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            $this->db->setAttribute(PDO::ATTR_TIMEOUT, 5); //Add this.
        }
        catch (PDOException $error) {
            echo '<b>An error occured!</b><br />' . $error->getMessage();
            exit();
        }
    }
}

This would make the query time out after 5 seconds instead of the 30 seconds you describe in your question. Please note that the underlying mysql engine has to support this as not all support it.

If you want your website to be accessible, even when you can't access the database, I see two solutions : caching the results of the query ; or caching the entire page.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM