【问题标题】:PDO disconnect and PHP variable referencePDO 断开连接和 PHP 变量引用
【发布时间】:2016-02-06 18:57:51
【问题描述】:

我是 PHP 高级新手。但对编程并不陌生。

我们有一个正在杀死我们的数据库的软件(已关闭但仍处于活动状态)。

里面使用了PDO 花了很多时间后的问题是PDO断开模式和使用了一个包装类里面的PDO。

public function connect() {
    if(!$this->connected){
        $col = 'mysql:host='
                .$this->parametri->getHOST()
                .';'
                .'dbname='
                .$this->parametri->getDB()
                .';'
                .'charset=utf8';

        try {
            // connessione tramite creazione di un oggetto PDO
            $db = new PDO($col , $this->parametri->getDBUSER(), 
                                 $this->parametri->getPASS());
            $this->pdoconn=$db;
            $this->connected=TRUE;
        }
        catch(PDOException $e) {
            $this->connected=FALSE;
            return NULL;
        }
    }
    return  $this->pdoconn;
}

public function getPDO(){
        if ($this->connected){
            return $this->pdoconn;
        }else {
            return NULL;
        }
    }

public function disconnect() {
        $this->pdoconn=null;
        $this->connected=FALSE;
    }

在官网阅读PDO文档和cmets当$this->pdoconn=null时连接被释放; 但它已通过 getPDO() 传递。

根据this articlethis dissertion,某处可能存在指向连接的变量,因此连接永远不会被释放;该类认为该连接已被释放,并且当请求创建一个新连接时,该连接会将最后一个连接丢失给该类的用户。

所以我们的想法是将连接 tu null 也传回 this 或者有另一种方法来保护 pdoconn 并强制为 null。

public function disconnect(&$var) {
     $var=null;
     $this->pdoconn=null;
     $this->connected=FALSE;
}

另一种方法是构建一个永远不会暴露 pdo 连接的包装类,并强制在其中执行查询以管理断开连接。

【问题讨论】:

  • 拥有一个分配连接的静态变量(单例)怎么样。几乎是您现在拥有的,但静态的,因此它重用相同的连接,因为静态将持续存在而不创建新的连接。
  • 两种方案都很有趣不知道该投哪一种
  • 试一试,看看您的数据库负载是否得到解决。

标签: php pdo php-5.2


【解决方案1】:

也许尝试建立连接和/或类singleton,然后它应该保持数据库连接,并且每次你去使用它时,它都会是同一个连接。如果你这样做,你不必每次使用它时都专注于关闭连接,因为整个页面只有一个连接。这是一个简单的例子:

class MyClass
    {
        // You can make the class itself persist to save on resources
        private static $obj;
        // You can save the connection specifically to reuse it
        private static $singleton;
        // Return itself to static var
        public function __construct()
            {
                if(!empty(self::$obj)) {
                    echo 'OLD OBJ<br />';
                    return self::$obj;
                }
                echo 'NEW OBJ<br />';
                self::$obj = $this;
                return self::$obj;
            }
        // Return connection if already set
        public function connect($username = "username",$password = "password",$host = "host",$database = "dbname")
            {
                if(!empty(self::$singleton)) {
                    echo 'OLD CONN<br />';
                    return self::$singleton;
                }

                try {
                     self::$singleton = new PDO('mysql:host='.$host.';dbname='.$database.';charset=utf8',$username,$password);
                }
                catch(PDOException $e) {
                    die('connection failed');
                }
                echo 'NEW CONN<br />';
                return  self::$singleton;
            }
    }

使用示例:

    // Creates first PDO connection
    $database = new MyClass();
    $con1 = $database->connect();

    function getConnection()
        {   
            // Creates first connection
            $database = new MyClass();
            return $database->connect();
        }

    // Won't create a new instance, but rather use the same.
    $con2 = getConnection();

会写:

NEW OBJ
NEW CONN
OLD OBJ
OLD CONN

【讨论】:

    【解决方案2】:

    这就是我实现单例数据库实例以保持持久数据库连接的方式:

    class DB implements IConnectInfo {
        public static function factory() {
            if( self::$_instance === null ) {
                self::$_instance = new DB( 'HOST', 'USERNAME', 'PASSWORD', 'DATABASE' );
            }
    
            return self::$_instance;
        }
    
        protected function __construct( $host, $username, $password, $database ) {
            try {
                $this->_link = new PDO( "mysql:host={$host};dbname={$database}", $username, $password, array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) );
                $this->_link->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
                $this->_link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            } catch(PDOException $e) {
                $this->_link = null;
                die( "ERROR: Could not connect to the database" );
            }
        }
    
        public function __destruct() {
            if ( $this->_hasActiveTransaction ) {
                $this->commit();
            }
        }
    
        final private function __clone() {
        }
    
        public function &link() {
            return $this->_link;
        }
    
        public function beginTransaction() {
            if ( $this->_hasActiveTransaction == false ) {
                try {
                    $this->_link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                    $this->_link->beginTransaction();
                    $this->_hasActiveTransaction = true;
                    return true;
                } catch (PDOException $e) {
                    error_log($e);
                    die();
                    return false;
                }
            }
    
            return true;
        }
    
        public function rollBack() {
            if( !$this->beginTransaction() ) {
                return false;
            }
    
            try {
                $this->_link->rollBack();
                $this->_hasActiveTransaction = false;
                return true;
            } catch (PDOException $e) {
                error_log($e);
                return false;
            }
        }
    
        public function commit() {
            if( !$this->beginTransaction() ) {
                return false;
            }
    
            try {
                $this->_link->commit();
                $this->_hasActiveTransaction = false;
                return true;
            } catch (PDOException $e) {
                $this->rollBack();
                return false;
            }
    
        }
    
        private $_hasActiveTransaction = false;
        private $_result = null;
        private $_link = null;
        static private $_instance = null;
    } 
    

    然后我就这样使用它:

    $DB = DB::factory();
    $query = "SELECT * FROM myTable";
    $stmt = $DB->link()->prepare( $query );
    $stmt->execute();
    while( $myTableObj = $stmt->fetch( PDO::FETCH_OBJ ) ) {
         echo $myTableObj->myField
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 2014-02-02
      相关资源
      最近更新 更多