请求超时,错误要比通过最长超时时间早得多

时间:2014-12-12 05:09:24

标签: php android database timeout database-connection

我的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秒的超时设置。

1 个答案:

答案 0 :(得分: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方法即可使用相同的连接。需要注意的是,该类是最终的,constructorclone函数是私有的,以防止重复此类和数据库连接。

另外请注意,您不必断开与数据库的连接,因为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();

因此,您现在可以看到,您可以拥有多个单身人士,每个单身人士只拥有一个与一个数据库的连接。使用此方法,没有首选项设置为第一次调用该类。没有需要进行初始连接。此外,您无需在整个地方不必要地复制数据库连接详细信息。

我要做的最后一个修改是添加一个像这样的快捷函数

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' );

您永远不知道您可能想要添加哪些功能,因此请始终保持这些选项的开放。

本质上,这是一个与Factory模式合并的Singleton模式。有关编程模式的更多详细信息,请参阅此Wiki文章

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