Время ожидания истекло, ошибка намного раньше, чем прошло максимальное время ожидания

0

Мое приложение для Android подключается к базе данных, много раз во многих действиях через PHP. в PHP, у меня есть этот код для подключения базы данных

   class db_connect 
   {
       protected $db_conn;
       protected $db_name = "database";
       protected $db_user;
       protected $password;
       protected $db_host ="localhost";


       function __construct($username,$pass) {

           $this->db_user = $username;
           $this->password = $pass;

       }

       function connect(){
           $this->db_conn = new PDO("mysql:host=$this->db_host;        
           dbname=$this->db_name",$this->db_user,$this->password);
           $this->db_conn->exec("set names utf8");
           return $this->db_conn;
       }
       function disconnect()
       {
           $this->db_conn = null;
       }

       function __destruct() {
       }
}

Поэтому, когда мне нужно подключить базу данных из другого класса, я просто делаю:

$dbconnect = new db_connect($user,$pass);
$connection = $dbconnect->connect();

то после выполнения, я отключу в качестве $dbconnect-> disconnect();

У моего Php5.ini есть это: (Я не хочу его менять).

; Default timeout for socket based streams (seconds)
  default_socket_timeout = 60

Но проблема в том, что когда я пытаюсь подключиться к базе данных, она отвечает сообщением "запрос тайм-аута" всего за 4/5 секунды. тогда, если я попробую еще раз, обычно он подключается. Может ли кто-нибудь предложить мне, что я делаю неправильно? Почему он отправляет сообщение с запросом времени за 5 секунд, даже если у меня есть 60 секунд времени.

Теги:
database
database-connection
timeout

1 ответ

1
Лучший ответ

Я не уверен, что у вас проблема (возможно, снова открыв закрытое соединение), однако я бы предложил использовать одноэлементный шаблон для вашего класса соединений.

Это выглядит примерно так

final class PdoWrapper{

    protected static $_instance;    
    protected $_conn;
    protected $db_name = "database";
    protected $db_user = "user";
    protected $password = "pass";
    protected $db_host ="localhost";

    private funciton __construct(){
        $this->_conn = new PDO("mysql:host=$this->db_host;dbname=$this->db_name",$this->db_user,$this->password);
        $this->_conn->exec("set names utf8");
    }

    private function __clone(){}

    public static getInstance(){
        if( !self::$_instance ){
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function getConnection(){
        return $this->_conn;
    }
}

И вы будете использовать его так

 $conn = PdoWrapper::getInstance()->getConnection();

Дело в том, что это будет поддерживать ваше соединение, поэтому вы всегда используете один и тот же метод, просто вызвав метод getInstance. Следует отметить, что класс является окончательным, а функции constructor и clone являются закрытыми для предотвращения дублирования этого класса и подключения к базе данных.

В качестве дополнительной заметки вам не нужно отключать базу данных, поскольку PHP будет делать это автоматически, когда скрипт заканчивается. Как правило, для подключения к базе данных требуется время, поэтому в конечном итоге вам лучше поддерживать одно единственное соединение, затем закрывать и открывать одно или открывать несколько соединений.

При воспроизведении необходимо, чтобы класс подключения принимал вход для параметров соединения.

Хотя это на первых швах очень разумная вещь и легко достигается, это несколько наивный взгляд. Чтобы объяснить это, возникает сложность, потому что, как только вы разрешаете ввод в класс, вы нарушаете характер шаблона "Singleton", который представляет собой единый экземпляр с единой точкой доступа, в основном неизменяемый экземпляр класса (после инициализации он не может быть изменен). Предотвращение мутации - это то, почему класс помечен как final (не может быть расширен) и имеет как частный __construct и __clone.

Лучший способ объяснить это - сказать, что вы отдаете предпочтение тому, когда создается одноэлемент, передавая детали соединения. Таким образом, вы всегда должны будете создать его с теми же данными о соединении или сначала сделать начальное соединение, прежде чем сможете его использовать. Чтобы еще больше усложнить это, вы открываете его для передачи в разных подробностях соединения, и с этим не будет четкого способа узнать, какой набор учетных данных использовался в любой момент времени или какое соединение он держит. У вас также будет проблема решить, был ли инициирован класс (соединение) с этими данными или если его необходимо повторно подключить, используя новые сведения о подключении.

К счастью, мы можем решить все эти проблемы, создав то, что я называю Multi-Singleton, что само по себе является оксюмороном. Во всяком случае, для этого вам понадобятся 2 файла, один для информации о соединении (файл конфигурации), так как вы не хотите, чтобы все данные о подключении к базе данных были посыпаны всем вашим приложением. Просто подумайте о том, когда вы хотите обновить свой пароль базы данных и вам придется искать весь свой код для его копий.

Итак, мы начнем с этого файла (dbconf.php)

<?php
$conf = array();

$conf['database1'] = array(
    'host' => 'localhost',
    'user' => 'user1',
    'pass' => 'pass1'
);

$conf['database2'] = array(
    'host' => 'localhost',
    'user' => 'user2',
    'pass' => 'pass2'
);

В этом файле мы имеем многомерный массив с ключом верхнего уровня, сопоставленным с именем базы данных, а остальные данные являются данными соединения для этой базы данных.

Затем мы делаем несколько незначительных изменений в вышеприведенном классе. (это не было проверено, но должно показать общую идею)

<?php
final class PdoWrapper{

    protected static $_instances = array(); 
    protected static $_dbconf;
    protected $_conn;

    private funciton __construct( $database ){
        if( !self::$_dbconf ){
            require 'dbconf.php';
            self::$_dbconf = $conf;
        }

        if( !isset( self::$_dbconf[$database] ) ){
            die( 'Unknown database in '.__FILE__.' on '.__LINE__ );
        }

        $this->_conn = new PDO(
            "mysql:host=" . self::_dbconf[$database]['host'] . ";dbname=$database",
            self::_dbconf[$database]['user'],
            self::_dbconf[$database]['pass']
        );
        $this->_conn->exec("set names utf8");
    }

    private function __clone(){}

    public static getInstance( $database ){
        if( !self::$_instance[$database] ){
            self::$_instance[$database] = new self($database);
        }
        return self::$_instance[$database];
    }

    public function getConnection(){
        return $this->_conn;
    }
}

Все, что здесь изменилось, это импорт файла конфигурации и способ сообщить классу, какой экземпляр базы данных использовать. Теперь с этими изменениями вы вызываете класс следующим образом.

 $Conn1 = PdoWrapper::getInstance( 'database1' )->getConnection();
 $Conn2 = PdoWrapper::getInstance( 'database2' )->getConnection();

Итак, как вы можете видеть, теперь вы можете иметь несколько Singletons, каждый из которых содержит ровно одно соединение с одной базой данных. С помощью этого метода нет предпочтения, заданного для первого вызова класса. Нет первоначального подключения, которое необходимо выполнить. Кроме того, вы не обязательно дублируете детали подключения к базе данных повсюду.

Одна из последних модификаций, которые я бы сделал, заключается в том, чтобы добавить функцию ярлыка, подобную этой

public static function getInstanceConnection( $database ){
    $I = self::getInstance( $database );
    return $I->getConnection();
}

Хотя это необязательно, вы можете сделать один звонок и немного лучше читать вне класса. Таким образом, чтобы дублировать код инициализации выше, вы сделали бы это после добавления этого метода в.

 $Conn1 = PdoWrapper::getInstanceConnection( 'database1' );
 $Conn2 = PdoWrapper::getInstanceConnection( 'database2' );

Причина не только возвращения соединения из метода getInstance (помимо ясности именования) заключается в том, что вам может понадобиться добавить некоторые другие функции для последнего класса, и в этом случае вам понадобится доступ к самому экземпляру Singleton. Простым примером этого с моей головы было бы добавить метод, чтобы увидеть, существует ли таблица как это.

public function tableExists( $table ){
    $stmt = $this->_conn->prepare('SHOW TABLES LIKE :table');
    $stmt->execute( array( ':table' => $table ) );
    return $stmt->rowCount() ? true : false;
}

Затем вам нужно будет вызвать экземпляр, чтобы вызвать его.

$I = PdoWrapper::getInstance( 'database1' );
$I->tableExists( 'table' );
//or with method chaining you can do this.
PdoWrapper::getInstance( 'database1' )->tableExists( 'table' );

Вы никогда не знаете, какую функциональность вы можете добавить последним, поэтому всегда оставляйте эти опции открытыми.

По существу это шаблон Singleton, объединенный с шаблоном Factory. Более подробную информацию о программировании шаблонов см. В этой статье в вики

http://en.wikipedia.org/wiki/Software_design_pattern

  • 0
    @ArtisticPhoenix, ценится. Я подам заявку и увижу это.
  • 0
    Это основной метод, который я использую, но я сократил класс, поэтому я не тестировал этот точный код, но он должен быть довольно близок. В своем полном коде я использую отдельный файл конфигурации PHP и имею экземпляр в качестве массива экземпляров, чтобы я мог подключаться к нескольким базам данных.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню