我的安卓应用程序通过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 会在脚本结束时自动执行此操作。 作为一般规则,连接到数据库需要时间,因此从长远来看,您最好保持一个连接打开,然后关闭并打开一个或打开多个连接。
重播为让连接类接受连接参数的输入。
虽然这乍一看是一件非常合理且容易实现的事情,但这有点幼稚的观点。为了解释这一点,就出现了复杂性,因为一旦你允许输入到类中,你就违反了"单例"模式的性质,这是一个具有统一访问点的单个实例,基本上是一个不可变的类实例(初始化后无法更改(。 防止突变是为什么该类被标记为final(不能扩展(并且同时具有私有__construct
和__clone
方法的原因。
解释这一点的最佳方法是,通过传入连接详细信息,表示您优先考虑创建单例的时间。 因此,您始终必须使用相同的连接详细信息创建它,或者先建立初始连接,然后才能使用它。 更复杂的是,您打开它以传递不同的连接详细信息,因此将没有明确的方法来知道在任何给定时间使用了哪组凭据或它持有什么连接。您还将面临一个问题,即确定类(连接(是使用此数据启动的,还是需要使用新的连接详细信息重新连接。
幸运的是,我们可以通过创建我所谓的多单例来解决所有这些问题,这本身就有点矛盾。 无论如何,为此,您将需要 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' );
您永远不知道以后可能要添加什么功能,因此请始终保持这些选项打开状态。
本质上,这是与工厂模式合并的单例模式。 有关编程模式的更多详细信息,请参阅此 wiki 文章
http://en.wikipedia.org/wiki/Software_design_pattern