Verbindungen und Verbindungsmanagement

Verbindungen und Verwaltung der Verbindungen

Verbindungen werden durch das Erstellen von Instanzen der PDO-Basisklasse erzeugt. Es ist unerheblich, welchen Treiber Sie benutzen wollen. Sie benutzen immer den PDO-Klassennamen. Der Konstruktor erwartet Parameter zur Angabe der Datenbankquelle (auch bekannt als DSN) und optional für Benutzername und Passwort (falls vorhanden).

Beispiel #1 Mit MySQL verbinden

<?php
$dbh
= new PDO('mysql:host=localhost;dbname=test', $user, $pass);
?>

Wenn es Fehler bei der Verbindung gibt, wird eine Ausnahme vom Typ PDOException geworfen. Sie können die Ausnahme abfangen, wenn Sie sich selbst um die Fehlerbedingung kümmern wollen, oder Sie können es einer globalen Routine zur Ausnahmebehandlung überlassen, die Sie mit set_exception_handler() konfigurieren.

Beispiel #2 Verbindungsfehler behandeln

<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
} catch (
PDOException $e) {
// z.B. nach einem Timeout versuchen, die Verbindung erneut aufzubauen
}

Warnung

Wie jede andere Exception kann auch PDOException entweder explizit über eine catch-Anweisung oder implizit über set_exception_handler() abgefangen werden. Andernfalls ist das Standardverhalten, eine nicht abgefangene Exception in einen E_FATAL_ERROR umzuwandeln. Der fatale Fehler enthält einen Backtrace, der Verbindungsdetails preisgeben könnte. Deshalb sollte die php.ini-Option display_errors auf einem Produktionsserver auf 0 gesetzt werden.

Bei erfolgreicher Verbindung zur Datenbank wird eine Instanz der PDO-Klasse an Ihr Skript zurückgegeben. Die Verbindung bleibt während der Lebensdauer des PDO-Objekts aktiv. Um die Verbindung zu beenden, müssen Sie das Objekt löschen, indem Sie sicherstellen, dass alle Referenzen darauf gelöscht werden - das erreichen Sie, indem Sie der Variable, die das Objekt beinhaltet, null zuweisen. Wenn Sie das nicht explizit tun, schließt PHP die Verbindung automatisch, wenn Ihr Skript endet.

Hinweis: Gibt es noch weitere Referenzen auf dieses PDO-Exemplar (wie etwa von einem PDOStatement-Exemplar, oder von anderen Variablen, die dasselbe PDO-Exemplar referenzieren), müssen diese ebenfalls entfernt werden (zum Beispiel durch die Zuweisung von null an die Variable, die das PDOStatement referenziert).

Beispiel #3 Eine Verbindung schließen

<?php
$dbh
= new PDO('mysql:host=localhost;dbname=test', $user, $pass);
// hier die Verbindung nutzen
$sth = $dbh->query('SELECT * FROM foo');

// und nachdem das erledigt ist, wird sie geschlossen
$sth = null;
$dbh = null;
?>

Viele Webanwendungen profitieren von persistenten Verbindungen zum Datenbankserver. Persistente Verbindungen werden nicht am Ende des Skripts geschlossen, sondern werden gecacht und wiederverwendet, wenn ein anderes Skript eine Verbindung mit denselben Daten anfordert. Der Cache an persistenten Verbindungen erlaubt Ihnen, den Overhead zu vermeiden, wenn jedesmal eine neue Verbindung geöffnet wird, sobald ein Skript mit der Datenbank kommunizieren muss, was sich in einer schnelleren Anwendung widerspiegelt.

Beispiel #4 Persistente Verbindungen

<?php
$dbh
= new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
?>

Der Wert der PDO::ATTR_PERSISTENT Option wird nach Boolean kovertiert (aktiviere/deaktiviere persistente Verbindungen), es sei denn es ist ein nicht-numerischer String; in diesem Fall ermöglicht es die Verwendung mehrerer persistenter Verbindungspools. Das ist nützlich, wenn unterschiedliche Verbindungen inkompatible Einstellungen verwenden, beispielsweise unterschiedliche Werte von PDO::MYSQL_ATTR_USE_BUFFERED_QUERY.

Hinweis:

Wenn Sie persistente Verbindungen verwenden wollen, müssen Sie PDO::ATTR_PERSISTENT im Array von Treiberoptionen setzen, das an den PDO-Konstruktor übergeben wird. Wenn Sie dieses Attribut mittels PDO::setAttribute() nach der Instanziierung des Objekts setzen, verwendet der Treiber keine persistenten Verbindungen.

Hinweis:

Wenn Sie den PDO-ODBC-Treiber benutzen und Ihre ODBC-Bibliotheken ODBC Connection Pooling unterstützen (unixODBC und Windows etwa, es könnte auch andere geben), dann wird empfohlen, dass sie keine persistenten PDO-Verbindungen benutzen, sondern das Cachen der Verbindungen der ODBC Connection Pooling-Schicht überlassen. Der ODBC Connection Pool wird mit anderen Modulen im Prozess geteilt. Wenn PDO also angewiesen wird die Verbindung zu cachen, wird diese Verbindung nie dem ODBC Connection Pool zurückgegeben, was darin resultiert, dass zusätzliche Verbindungen aufgebaut werden, um jene anderen Module zu bedienen.

add a note add a note

User Contributed Notes 13 notes

up
178
cappytoi at yahoo dot com
10 years ago
Using PHP 5.4.26, pdo_pgsql with libpg 9.2.8 (self compiled). As usual PHP never explains some critical stuff in documentation. You shouldn't expect that your connection is closed when you set $dbh = null unless all you do is just instantiating PDO class. Try following:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.1;port=5432;dbname=anydb', 'anyuser', 'pw');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM sometable');
$stmt->execute();
$pdo = null;
sleep(60);
?>

Now check your database. And what a surprise! Your connection hangs for another 60 seconds. Now that might be expectable because you haven't cleared the resultset.

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$stmt->closeCursor();
$pdo = null;
sleep(60);
?>

What teh heck you say at this point? Still same? Here is what you need to do to close that connection:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$stmt->closeCursor(); // this is not even required
$stmt = null; // doing this is mandatory for connection to get closed
$pdo = null;
sleep(60);
?>

PDO is just one of a kind because it saves you to depend on 3rd party abstraction layers. But it becomes annoying to see there is no implementation of a "disconnect" method even though there is a request for it for 2 years. Developers underestimate the requirement of such a method. First of all, doing $stmt = null  everywhere is annoying and what is most annoying is you cannot forcibly disconnect even when you set $pdo = null. It might get cleared on script's termination but this is not always possible because script termination may delayed due to slow client connection etc.

Anyway here is how to disconnect forcibly using postgresql:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$pdo->query('SELECT pg_terminate_backend(pg_backend_pid());');
$pdo = null;
sleep(60);
?>

Following may be used for MYSQL: (not guaranteed)
KILL CONNECTION_ID()
up
9
d dot bergloev at gmail dot com
8 years ago
I would please advice people who talk about database port in reference with socket files to please read up about what a socket file is. TCP/IP uses ports, a socket file however is a direct pipe line to your database. So no, you should not replace localhost with local ip if you use a different port on your database server, because the socket file has nothing to do with your TCP/IP setup. And whenever possible, using the local socket file is much faster than establishing new TCP/IP connections on each request which is only meant for remote database servers.
up
17
jak dot spalding at gmail dot com
13 years ago
Just thought I'd add in and give an explanation as to why you need to use 127.0.0.1 if you have a different port number.

The mysql libraries will automatically use Unix sockets if the host of "localhost" is used. To force TCP/IP you need to set an IP address.
up
11
ogierschelvis at gmail dot com
9 years ago
As http://stackoverflow.com/questions/17630772/pdo-cannot-connect-remote-mysql-server points out; sometimes when you want to connect to an external server like this:

<?php
$conn
= new PDO('mysql:host=123.4.5.6;dbname=test_db;port=3306','username','password');
?>

it will fail no matter what. However if you put a space between mysql: and host like this:

<?php
$conn
= new PDO('mysql: host=123.4.5.6;dbname=test_db;port=3306','username','password');
?>

it will magically work. I'm not sure if this applies in all cases or server setups. But I think it's worth mentioning in the docs.
up
3
Moshe Dolev
6 years ago
Please note that you cannot use persistent connections to create temporary tables in mysql/mariadb.
Tables you create using a statement like "create temporary table TABLE1 ..." are destroyed only when the mysql session ends (not php session !). This never happens if you use a persistent connection.
If you create a temporary table on a persistent connection, the table will live even after the php script ends. The next php script that will try to issue the same create temporary table statement, will receive an error.
IMHO, this fact makes persistent connections quite useless.
up
16
neville at whitespacers dot com
15 years ago
To avoid exposing your connection details should you fail to remember to catch any exception thrown by the PDO constructor you can use the following class to implicitly change the exception handler temporarily.

<?php

Class SafePDO extends PDO {

        public static function
exception_handler($exception) {
           
// Output the exception details
           
die('Uncaught exception: ', $exception->getMessage());
        }

        public function
__construct($dsn, $username='', $password='', $driver_options=array()) {

           
// Temporarily change the PHP exception handler while we . . .
           
set_exception_handler(array(__CLASS__, 'exception_handler'));

           
// . . . create a PDO object
           
parent::__construct($dsn, $username, $password, $driver_options);

           
// Change the exception handler back to whatever it was before
           
restore_exception_handler();
        }

}

// Connect to the database with defined constants
$dbh = new SafePDO(PDO_DSN, PDO_USER, PDO_PASSWORD);

?>
up
9
dan dot franklin at pearson dot com
16 years ago
Note that you can specify a port number with "port=####", but this port number will be ignored if the host is localhost.  If you want to connect to a local port other than the default, use host=127.0.0.1 instead of localhost.
up
5
edsanhu at gmail dot com
9 years ago
For being able to retrieve information from the db in utf-8 the connection assignment has to add to the dsn `charset=utf8`:

<?php
$dbh
= new PDO('mysql:host=localhost;dbname=test;charset=utf8', $user, $pass);
?>
up
0
antony at harrisretail dot co dot uk
4 years ago
It's not possible to use a persistent connection and to extend the PDOStatement class to add methods to the standard class. This means that you cannot do:

<?php
  $dbh
= new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
 
$dbh->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement', array($this)));
?>

This results in an error:

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances
up
1
thz at plista dot com
11 years ago
If you are using PHP 5.4 and later, you can no longer use persistent connections when you have your own database class that derives from the native PDO object. If you do, you will get segmentation faults during the PHP process shutdown.

Please see this bug report for more information: https://bugs.php.net/bug.php?id=63176
up
-3
me+nospam at tati dot pro
8 years ago
If you want to keep connection after fork exit, you can kill with SIGKILL forked process.

<?php
$dbh
= new PDO('pgsql:host=localhost;dbname=test', $user, $pass);
$pid = pcntl_fork();
if(
$pid == 0){
       
// forked process 'll exit immediately
       
exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);
?>
Result: false

<?php
$dbh
= new PDO('pgsql:host=localhost;dbname=test', $user, $pass);
$pid = pcntl_fork();
if(
$pid == 0){
       
// use sigkill to close process
       
register_shutdown_function(function(){
               
posix_kill(getmypid(), SIGKILL);
        });
       
// forked process 'll exit immediately
       
exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);
?>
Result: object(PDOStatement)#3 (1) {
  ["queryString"]=>
  string(8) "select 1"
}
up
-5
alvaro at demogracia dot com
13 years ago
On connection errors, the PDO constructor seems to do two things no matter your PDO::ATTR_ERRMODE setting:

1. Trigger a warning
2. Throw a PDOException

If you set the PDO::ATTR_ERRMODE parameter, it will only take effect on further operations.
up
-63
paulo dot sistema at gmail dot com
7 years ago
Hello guys!
Has anyone used the ORACLE WALLET feature in PHP or Java?

https://docs.oracle.com/middleware/1213/wls/JDBCA/oraclewallet.htm#JDBCA596

I would like to know how to implement it because I can not implement. We use PDO + PHP in all applications and now there is this demand of the DBA.

Thank you
To Top