Отключение 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 ().

Согласно этой статье и this dissertion, где-то может быть переменная, указывающая на соединение, поэтому соединение никогда не будет освобожден; класс думает, что соединение освобождено, и при запросе создает новое соединение, теряя последнее для пользователя класса.

Итак, идея состоит в том, чтобы передать обратно соединение tu null, также это или есть другой способ защитить pdoconn и принудительно установить значение null.

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

Другой способ - создать другой класс обертывания, который никогда не будет открывать соединение pdo и принудительно выполнять запрос внутри него, чтобы управлять также отключением.


person user1594895    schedule 06.02.2016    source источник
comment
Как насчет статической переменной (singleton), которой вы назначаете соединение. Почти то, что у вас есть сейчас, но статическое, поэтому оно повторно использует одно и то же соединение, потому что статическое будет сохраняться без создания новых подключений.   -  person Rasclatt    schedule 07.02.2016
comment
Оба решения очень интересны, я не знаю, за какое проголосовать   -  person user1594895    schedule 08.02.2016
comment
Попробуйте один из них и посмотрите, разрешится ли ваша нагрузка на базу данных.   -  person Rasclatt    schedule 08.02.2016


Ответы (2)


Возможно, попробуйте установить соединение и / или класс 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
person Rasclatt    schedule 06.02.2016

Вот как я реализовал одноэлементный экземпляр БД, чтобы поддерживать постоянное соединение с БД:

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
}
person Alon Eitan    schedule 07.02.2016