PDO schließt Verbindung


120

Nur eine ziemlich einfache Frage in Bezug auf PDO im Vergleich zu MySQLi.

Mit MySQLi können Sie die Verbindung schließen, indem Sie Folgendes tun:

$this->connection->close();

Bei PDO heißt es jedoch, dass Sie die Verbindung öffnen, indem Sie:

$this->connection = new PDO();

aber um die Verbindung zu schließen, stellen Sie sie ein null.

$this->connection = null;

Ist das richtig und wird dadurch die PDO-Verbindung tatsächlich freigegeben? (Ich weiß, dass es so funktioniert, wie es eingestellt ist null.) Ich meine, mit MySQLi müssen Sie eine Funktion ( close) aufrufen , um die Verbindung zu schließen. Ist PDO so einfach wie = nulldas Trennen? Oder gibt es eine Funktion zum Schließen der Verbindung?


11
Der Grund, den ich frage, ist, dass ich nicht sicher bin, ob ich die Verbindung richtig geschlossen habe. aber nein nicht wirklich nur fasziniert
Liam Sorsby

2
Die Datenbankverbindung wird automatisch geschlossen, wenn Ihr PHP-Skript die Ausführung beendet.
Martin Bean

3
Wenn Sie damit fertig sind, können Sie es beenden, insbesondere wenn nach Abschluss der Interaktion mit der Datenbank zeitaufwändiger Code vorhanden ist. Allerdings sehe ich das Problem nicht wirklich darin, darauf zu warten, dass das Skript beendet wird (abgesehen davon, dass die Verbindungen zum DB-Server reduziert werden)
Kieran,

3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Finden Sie selbst heraus, wie es funktioniert: P
Flosculus

23
Nicht alle PHP-Skripte sind von kurzer Dauer. Es gibt PHP-Dämonen da draußen. Ich denke, das ist eine großartige Sache, um es persönlich zu klären.
datUser

Antworten:


146

Laut Dokumentation sind Sie korrekt ( http://php.net/manual/en/pdo.connections.php ):

Die Verbindung bleibt für die Lebensdauer dieses PDO-Objekts aktiv . Um die Verbindung zu schließen, müssen Sie das Objekt zerstören, indem Sie sicherstellen, dass alle verbleibenden Verweise darauf gelöscht werden. Dazu weisen Sie der Variablen, die das Objekt enthält, NULL zu. Wenn Sie dies nicht explizit tun, schließt PHP die Verbindung automatisch, wenn Ihr Skript endet .

Beachten Sie, dass beim Initialisieren des PDO-Objekts als dauerhafte Verbindung die Verbindung nicht automatisch geschlossen wird.


4
Was ist, wenn ich einen Prozess habe, der nicht endet? zB Websocket. Gibt es eine Möglichkeit, keine dauerhafte Verbindung zu verwenden?
Rafael Moni

1
Bei dauerhaften Verbindungen in einem Skript, das über einen längeren Zeitraum ausgeführt wird, können Sie absichtlich (oder versehentlich) Verbindungen mit einem Timeout (z. B. in my.ini) oder aus einer Reihe anderer Gründe beenden lassen. Wenn Sie eine Abfrage verbinden oder ausführen, stellen Sie einen Fehler fest. Wenn "MySQL ist verschwunden", versuchen Sie erneut, eine Verbindung herzustellen, oder führen Sie die Abfrage ein zweites Mal aus.
Frank Forte

1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionAber wenn eine Verbindung dauerhaft ist und ich sie explizit mit NULL aufrufe, bevor das Skript endet, wird sie geschlossen, auch wenn sie dauerhaft ist, richtig?
Tonix

1
@tonix Nein, es sollte veröffentlicht (einem anderen Skript zur Verfügung gestellt), aber nicht geschlossen werden.
Benjamin

2
@tonix Ich denke schon, ja. Zitat aus dem PHP-Handbuch zu dauerhaften Verbindungen : " Warnung Bei der Verwendung dauerhafter Verbindungen sind einige zusätzliche Vorsichtsmaßnahmen zu beachten. Eine davon ist, dass bei Verwendung der Tabellensperre für eine dauerhafte Verbindung das Skript aus irgendeinem Grund die Sperre nicht aufheben kann. Nachfolgende Skripts, die dieselbe Verbindung verwenden, werden auf unbestimmte Zeit blockiert und erfordern möglicherweise einen Neustart des httpd-Servers oder des Datenbankservers. "
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 Ich denke, es ist ein sehr schlechtes Muster, besonders wenn ein Entwickler mehrere Kopien der PDO-Referenz speichern könnte. $ a = neues PDO (...); $ b = $ a; $ a = null; Dort bleibt Ihr PDO-Objekt für immer geöffnet (in einem daemonähnlichen PHP-Programm). Dies gilt insbesondere dann, wenn die PDO-Referenz über Funktionen und Objekteigenschaften läuft und Sie nie sicher sind, alle auf Null zu setzen.
Gabriel

33
Es sollte eine -> close () -Methode für PDO geben.
Gabriel

5
Ein weiterer Grund, PDO nicht zu mögen.
José Carlos PHP

6
@ Gabriel - Ich schlage vor, dass das "Speichern mehrerer Kopien" ein noch schlechteres Muster ist.
Rick James

4
Dies funktioniert nicht, wenn Sie ein PDOStatement-Objekt zwischen diesen beiden Zeilen erstellt haben (dh in jeder praktischen Situation). Um die Verbindung zu schließen, müssen Sie sowohl das PDO-Objekt als auch das PDOStatement-Objekt auf null setzen. Siehe hier: php.net/manual/en/pdo.connections.php#114822
Ilmari

8

Es ist mehr als nur das Setzen der Verbindung auf Null. Das mag in der Dokumentation stehen, aber das ist nicht die Wahrheit für MySQL. Die Verbindung bleibt etwas länger bestehen (ich habe 60s gehört, aber nie getestet)

Wenn Sie hier die vollständige Erklärung wünschen, lesen Sie diesen Kommentar zu den Verbindungen https://www.php.net/manual/en/pdo.connections.php#114822

Um das Schließen der Verbindung zu erzwingen, müssen Sie so etwas tun

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

Vielen Dank für Ihre Antwort. Die Frage war vor einiger Zeit, aber Sie haben Recht mit der Verbindung.
Liam Sorsby

Ich stimme nicht wirklich zu, dass es eine gute Idee ist, mit der TCP-Verbindung über PHP zu spielen. Die gesamte Behandlung von TCP-Verbindungen auf niedriger Ebene wird abstrahiert, sodass wir uns zur Laufzeit nur mit der Klasse und den Objekten auf hoher Ebene befassen müssen. PHP ist eine anforderungsbasierte Sprache (wie Sie wahrscheinlich wissen), sodass das Beenden einer potenziell dauerhaften Verbindung zum dB wahrscheinlich zu unerwarteten Fehlern / Problemen für Benutzer führt. Der Anwendungsfall, auf den Sie verlinken, ist wahrscheinlich das Ergebnis, dass der Treiber die dauerhafte Verbindung offen hält, um von einer anderen Anforderung verwendet zu werden. Ich hätte also gedacht, dass dies das erwartete Verhalten ist.
Liam Sorsby

Wenn Sie sich die Prozessliste in MySQL ansehen, wird die Verbindung noch angezeigt. Ich bin damit einverstanden, dass Sie nicht so mit der TCP-Verbindung herumspielen, und es sollte eine Möglichkeit geben, die Verbindung ordnungsgemäß zu trennen. Das ist aber nicht der Fall. Wenn Sie also wirklich die Verbindung zum Server trennen möchten, müssen Sie so etwas tun. Wenn Sie die Verbindung auf null setzen, wird die Verbindung nicht von dem getrennt, was in den Dokumenten angegeben ist.
Jdahern

Ich habe diese Erklärung
Fil

7

Ich habe eine abgeleitete Klasse erstellt, um eine selbstdokumentierendere Anweisung anstelle von "$ conn = null;" zu erhalten.

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;
    }
}

So kann ich meinen Code aufrufen zwischen:

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

1
Sie können die CMyPDO :: __ construct () -Methode privat machen und dort ein Singleton-Muster verwenden.
Aditya Hajare

Ja, das ist möglich. Sie müssen Verbindungsinformationen auch mit einer anderen Methode zuweisen, wenn Sie mehr als eine Datenbank gleichzeitig verwenden. Der Unterschied ist minimal, nur haben Sie etwas mehr Anweisungen zum Aufrufen von Instanzmethoden.
Fil

@AdityaHajare Sie können eine öffentliche Methode einer Oberklasse nicht privat in einer Unterklasse machen ..
nickdnk

@nickdnk, du hast recht. Was ich damit meinte, war, eine eigenständige CMyPDO-Klasse zu erstellen (ohne das PDO zu erweitern) und dann eine Datenbankinstanz in einem privaten Konstruktor der CMyPDO-Klasse (neue PDO-Klasse ($ dsn, $ dbuser, $ dbpass);) zu erstellen, wobei nur eine sichergestellt wurde Instanz ist in der gesamten Anwendung verfügbar (Singleton Design Pattern).
Aditya Hajare

1
@Fil Der Code "außerhalb" closeConnectionsollte jedoch nicht wissen, dass er einen Verweis auf die Variable kopieren muss, anstatt das Objekt zuzuweisen . Mit anderen Worten, Ihre Art, eine enge PDO-Funktion zu codieren, hat schlimme Nebenwirkungen und macht sie unzuverlässig. Die einzige Möglichkeit, dies zu tun, besteht darin, closeConnectionzu überprüfen, wie viele Verweise auf das PDO-Objekt im Code vorhanden sind, und zu werfen, falls mehr als 1 vorhanden ist.
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

Vollständiges Beispiel mit benutzerdefinierter Klasse PDO2.


1
Bitte entfernen Sie entweder try catch aus Ihrem Code oder fügen Sie einen neuen Wurf hinzu, wie hier gezeigt . Im Moment missbraucht Ihr Code sowohl Ausnahmen als auch Fehlerberichte im Allgemeinen
Ihr gesunder Menschenverstand
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.