PDO chiusura connessione


120

Solo una domanda piuttosto semplice per quanto riguarda il PDO rispetto a MySQLi.

Con MySQLi, per chiudere la connessione potresti fare:

$this->connection->close();

Tuttavia con PDO si afferma che si apre la connessione utilizzando:

$this->connection = new PDO();

ma per chiudere la connessione è stata impostata null.

$this->connection = null;

È corretto e questo libererà effettivamente la connessione PDO? (So ​​che funziona come è impostato su null.) Voglio dire con MySQLi devi chiamare una funzione ( close) per chiudere la connessione. PDO è facile quanto = nulldisconnettersi? Oppure c'è una funzione per chiudere la connessione?


11
il motivo per cui lo chiedo è che non sono sicuro di aver chiuso correttamente la connessione. ma no, non solo incuriosito
Liam Sorsby

2
La connessione al database viene chiusa automaticamente quando lo script PHP interrompe l'esecuzione.
Martin Bean

3
Se hai finito di usarlo, perché non andare avanti e terminarlo, soprattutto se c'è del codice che richiede tempo una volta che hai finito di interagire con il database. Tuttavia, non vedo davvero il problema con l'attesa del termine dello script (oltre a ridurre le connessioni al server DB).
Kieran


23
Non tutti gli script php hanno vita breve. Ci sono demoni php là fuori. Penso che questa sia un'ottima cosa da chiarire personalmente.
datUser

Risposte:


146

Secondo la documentazione hai ragione ( http://php.net/manual/en/pdo.connections.php ):

La connessione rimane attiva per la durata di quell'oggetto PDO . Per chiudere la connessione, è necessario distruggere l'oggetto assicurandosi che tutti i riferimenti rimanenti ad esso vengano eliminati - lo si fa assegnando NULL alla variabile che contiene l'oggetto. Se non lo fai esplicitamente, PHP chiuderà automaticamente la connessione al termine dello script .

Notare che se si inizializza l'oggetto PDO come connessione persistente, la connessione non verrà chiusa automaticamente.


4
E se ho un processo che non finisce? ad esempio websocket. C'è un modo per non utilizzare la connessione persistente?
Rafael Moni

1
Per le connessioni persistenti in uno script che viene eseguito per un lungo periodo, è possibile intenzionalmente (o accidentalmente) avere connessioni interrotte con un timeout (ad esempio in my.ini) o per una serie di altri motivi. Quando ci si connette o si esegue una query, rilevare eventuali errori e, se è "MySQL è andato via", provare a connettersi di nuovo o eseguire la query una seconda volta.
Frank Forte

1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionMa se una connessione è persistente e chiamo esplicitamente NULL su di essa prima che lo script finisca, verrà chiusa anche se è persistente, corretto?
tonix

1
@tonix No, dovrebbe essere rilasciato (reso disponibile per un altro script), ma non chiuso.
Benjamin

2
@tonix Penso di sì, sì. Citazione dal manuale PHP sulle connessioni persistenti : " Attenzione Ci sono un paio di avvertenze aggiuntive da tenere a mente quando si usano connessioni persistenti. Una è che quando si usa il blocco della tabella su una connessione persistente, se lo script per qualsiasi motivo non può rilasciare il blocco, quindi gli script successivi che utilizzano la stessa connessione verranno bloccati a tempo indeterminato e potrebbero richiedere il riavvio del server httpd o del server database. "
Benjamin

46
$conn=new PDO("mysql:host=$host;dbname=$dbname",$user,$pass);
    // If this is your connection then you have to assign null
    // to your connection variable as follows:
$conn=null;
    // By this way you can close connection in PDO.

11
IMHO penso che sia un modello pessimo, specialmente quando uno sviluppatore potrebbe memorizzare diverse copie del riferimento pdo. $ a = nuovo DOP (...); $ b = $ a; $ a = null; Lì, il tuo oggetto PDO rimarrà aperto per sempre (in un programma php simile a un demone). Ciò è particolarmente vero quando il riferimento PDO viaggia attraverso funzioni e proprietà degli oggetti e non si è mai sicuri di annullarli tutti.
Gabriel

33
Dovrebbe esserci un metodo -> close () su PDO.
Gabriel

5
Un altro motivo per non amare il DOP.
José Carlos PHP

6
@ Gabriel - Suggerisco che la "memorizzazione di più copie" sia uno schema ancora peggiore.
Rick James

4
Questo non funziona se hai creato un oggetto PDOStatement tra queste due righe (cioè in ogni situazione pratica). Per chiudere la connessione, è necessario impostare sia l'oggetto PDO che l'oggetto PDOStatement su null. Vedi qui: php.net/manual/en/pdo.connections.php#114822
Ilmari

8

È più che impostare la connessione su null. Potrebbe essere quello che dice la documentazione, ma non è la verità per mysql. La connessione rimarrà un po 'più a lungo (ho sentito gli anni '60, ma non l'ho mai testato)

Se vuoi qui la spiegazione completa vedi questo commento sui collegamenti https://www.php.net/manual/en/pdo.connections.php#114822

Per forzare la chiusura della connessione devi fare qualcosa di simile

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;

La ringrazio per la risposta. La domanda era di un bel po 'di tempo fa, ma hai ragione sulla connessione.
Liam Sorsby

In realtà non sono d'accordo che scherzare con la connessione TCP tramite PHP sia una buona idea. Tutta la gestione della connessione TCP di basso livello viene asportata in modo che dobbiamo solo occuparci della classe e degli oggetti di alto livello durante il runtime. PHP è un linguaggio basato sulle richieste (come probabilmente saprai), quindi l'uccisione di una connessione potenzialmente persistente al dB comporterà probabilmente errori / problemi imprevisti per gli utenti. Il caso d'uso a cui ti colleghi è probabilmente il risultato nel driver che mantiene aperta la connessione persistente per essere utilizzata da un'altra richiesta, quindi avrei pensato che questo sarebbe stato un comportamento previsto.
Liam Sorsby

Se guardi effettivamente l'elenco dei processi in mysql, mostrerà la connessione ancora lì. Sono d'accordo che non dovresti interferire con la connessione TCP in questo modo, e dovrebbe esserci un modo per disconnetterti correttamente dalla connessione. Ma non è così. Quindi, se vuoi davvero disconnetterti dal server, dovrai fare qualcosa del genere. L'impostazione della connessione su null non disconnette il contratto di connessione da ciò che dicono i documenti.
Jdahern

Ho trovato questa spiegazione: stackoverflow.com/a/18277327/1315873
Fil

7

Ho creato una classe derivata per avere un'istruzione più auto-documentante invece di "$ conn = null;".

class CMyPDO extends PDO {
    public function __construct($dsn, $username = null, $password = null, array $options = null) {
        parent::__construct($dsn, $username, $password, $options);
    }

    static function getNewConnection() {
        $conn=null;
        try {
            $conn = new CMyPDO("mysql:host=$host;dbname=$dbname",$user,$pass);
        }
        catch (PDOException $exc) {
            echo $exc->getMessage();
        }
        return $conn;
    }

    static function closeConnection(&$conn) {
        $conn=null;
    }
}

Quindi posso chiamare il mio codice tra:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);

1
Puoi rendere privato il metodo CMyPDO :: __ construct () e utilizzare il pattern singleton lì ..
Aditya Hajare

Sì, è possibile. È inoltre necessario assegnare le informazioni di connessione con un altro metodo se si utilizza più di un database alla volta. La differenza è minima, solo che hai poche istruzioni più lunghe per chiamare i metodi di istanza.
Fil

@AdityaHajare Non puoi rendere privato un metodo pubblico di una superclasse in una sottoclasse ..
nickdnk

@nickdnk, hai ragione. Quello che intendevo era creare una classe CMyPDO standalone (senza farla estendere PDO) e quindi creare un'istanza di database all'interno di un costruttore privato di CMyPDO (new PDO ($ dsn, $ dbuser, $ dbpass);) classe assicurandone solo uno l'istanza è disponibile in tutta l'applicazione (Singleton Design Pattern).
Aditya Hajare

1
@Fil Ma il codice "esterno" closeConnectionnon dovrebbe essere consapevole del fatto che ha bisogno di copiare il riferimento alla variabile invece di assegnare l'oggetto. In altre parole, il tuo modo di provare a codificare una funzione PDO chiusa ha effetti collaterali negativi, rendendola inaffidabile. L'unico modo per farlo sarebbe closeConnectioncontrollare quanti riferimenti all'oggetto PDO esistono nel codice e lanciare nel caso ne esista più di 1.
Xenos

-1
<?php if(!class_exists('PDO2')) {
    class PDO2 {
        private static $_instance;
        public static function getInstance() {
            if (!isset(self::$_instance)) {
                try {
                    self::$_instance = new PDO(
                        'mysql:host=***;dbname=***',
                        '***',
                        '***',
                        array(
                            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_general_ci",
                            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION
                        )
                    );
                } catch (PDOException $e) {
                    throw new PDOException($e->getMessage(), (int) $e->getCode());
                }
            }
            return self::$_instance;
        }
        public static function closeInstance() {
            return self::$_instance = null;
        }
    }
}
$req = PDO2::getInstance()->prepare('SELECT * FROM table');
$req->execute();
$count = $req->rowCount();
$results = $req->fetchAll(PDO::FETCH_ASSOC);
$req->closeCursor();
// Do other requests maybe
// And close connection
PDO2::closeInstance();
// print output

Esempio completo, con classe personalizzata PDO2.


1
Si prega di rimuovere try catch dal codice o aggiungere un nuovo lancio all'interno come mostrato qui . In questo momento il tuo codice abusa sia delle eccezioni che della segnalazione degli errori in generale
Il tuo buon senso il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.