PDO断开连接和PHP变量引用



我是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文档和评论,当$this->pdoconn=null时,连接被释放;但它已经通过 getPDO(( 传递。

根据这篇文章和这个论述,某处可能有一个变量指向连接,所以连接永远不会被释放;类认为连接被释放了,当请求创建一个新连接时,最后一个连接会丢失给类的用户。

所以这个想法是传回连接 tu null 也这样,或者还有另一种方法来保护 pdoconn 并强制为空。

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

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

也许尝试将连接和/或类设置为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

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

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
}

最新更新