Мое приложение для 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-> разъединение ();
Мой Php5.ini имеет это: (Я не хочу менять его).
; Default timeout for socket based streams (seconds)
default_socket_timeout = 60
Но проблема в том, что, когда я пытаюсь подключиться к базе данных, она отвечает сообщением «время ожидания запроса истекло», всего за 4/5 секунд. затем, если я попробую еще раз, обычно это связано.
Кто-нибудь может подсказать, пожалуйста, что я делаю не так? Почему он отправляет сообщение о превышении времени ожидания запроса через 5 секунд, даже если у меня установлено время ожидания 60 секунд.
Я не уверен сразу, в чем ваша проблема (возможно, повторное открытие незакрытого соединения), однако я бы предложил использовать шаблон синглтона для вашего класса соединения.
Это выглядит примерно так
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», который является единичным экземпляром с единой точкой доступа, в основном неизменным экземпляром класса (не может быть изменен после инициализации). Предотвращение мутации — вот почему класс помечается как окончательный (не может быть расширен) и имеет как частный __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();
Итак, как вы можете видеть, у вас может быть несколько синглетов, каждый из которых содержит ровно одно соединение с одной базой данных. При использовании этого метода предпочтение не устанавливается первому обращению к классу. Нет первоначального подключения, которое должно быть сделано. Кроме того, вам не нужно дублировать данные подключения к базе данных повсюду.
Последнее изменение, которое я хотел бы сделать, — добавить функцию ярлыка, подобную этой
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. Более подробную информацию о шаблонах программирования смотрите в этой вики-статье.
Других решений пока нет …