Sie sind hier : sebastian1012.bplaced.net/ homepage-neu / kreuz-und-quer / tutorials-info-neuigkeiten-datenbank / lazy-connecting-und-warum-eine-datenbank-klasse-sinnvoll-ist.php

Lazy Connecting und warum eine Datenbank-Klasse sinnvoll ist

Seit längerer Zeit gibt es heute mal wieder einen Artikel rund um die Architektur von PHP-Anwendungen hinsichtlich des Datenbankzugriffs. Genauer gesagt soll es um den Zweck einer PHP-Klasse zum Ausführen von SQL-Querys gehen.

PHP bietet ja bereits von Hause aus für viele Datenbanken Funktionen zum Verbinden, Abfragen usw. an. Für welche Datenbank man sich entscheidet, ist erstmal jedem selbst überlassen. Die Einbindung in PHP sollte aber möglichst einfach, universell, sicher und performant sein.

Die verschiedenen datenbankspezifischen Funktionen machen insbesondere den Punkt „Universell“ schwierig. Universell würde in meinen Augen bedeuten, dass man ohne großen Aufwand die darunterliegende Datenbank wechseln kann (z.B. von MySQL zu Oracle). Das ist mit Abstraktionslayern wie PDO möglich. Warum geht das aber in der Praxis oft nur schwer?

In der Praxis sieht es aber oft so aus:
Webanwendungen wachsen mit der Zeit. Am Anfang wird etwas programmiert, später erweitert, noch mehr erweitert usw. Die Altlasten wird man oft nur schwer wieder los. So auch bei den Datenbanken: Man entscheidet sich beispielsweise für MySQL und nutzt die PHP-MySQL-Funktionen. Das funktioniert auch alles – allerdings müsste im Falle des Wunsches auf eine andere Datenbanksoftware umzuziehen die gesamte Anwendung umgeschrieben werden (d.h. jedes Script, in dem mindestens eine mysql_* Funktion vorkommt). Diese Arbeit rentiert sich kaum.

Auch hinsichtlich der Sicherheit gibt es oft Probleme, wenn man einfach die mysql_*-Funktionen verwendet. Man muss bei jeder Abfrage daran denken, mysql_real_escape_string() oder intval() oder andere Filterfunktionen für sämtliche von außen kommende Eingaben einzusetzen, damit SQL-Injections verhindert werden.

Aus diesen Gründen sollte man sich von Anfang an für eine eigene Datenbank-Klasse entscheiden. Es gibt jede Menge solcher fertigen Klassen, z.B. bei PHP Classes – oder man schreibt sie sich schnell selbst…

Nun möchte ich aber noch zum Punkt Performance kommen. Die meisten Web-Anwendungen gehen so vor:

  1. in jedes Script wird eine globale Funktionsdatei eingebunden
  2. in dieser Funktiondatei wird die Verbindung zur Datenbank hergestellt
  3. im eigentlichen Script kann nun stets auf die Datenbank zugegriffen werden

Das funktioniert auch bestens, allerdings möchte ich auf ein Problem aufmerksam machen: MySQL (und andere Datenbanken auch) hat eine Konfigurationsvariable zum Einstellen der maximalen gleichzeitigen Verbindungen (max_connections). Erfolgen mehr gleichzeitige Zugriffe als in der Variable eingestellt sind, so kommt es zum Fehler Too many connections (englische Dokumentation, da ausführlicher). Bedenkenlos erhöhen kann man die Variable leider auch nicht. Es gilt deshalb – wie mit allen Ressourcen – sparsam damit umzugehen.

Das Problem ist, dass immer zu Beginn eines Scripts eine Datenbankverbindung geöffnet und (meist) erst nach Ausführung des Scripts wieder geschlossen wird – und das unabhängig davon, ob die Datenbank überhaupt benötigt wird.
Nun könnte man sagen, dass man die Include-Datei für die DB-Verbindung eben nur in den Scripten einfügt, in denen sie auch benötigt wird. Das ist schon mal ein guter Ansatz, aber es gibt auch Fälle, in denen zu Beginn des Scrips noch gar nicht klar ist, ob die Datenbank benötigt wird – etwa, wenn die Seite aus dem Cache (entweder gecachte HTML-Dokumente auf dem Server oder aus dem Browser-Cache) geladen werden kann und somit die Datenbank ebenfalls nicht gebraucht wird.

Um möglichst sparsam mit DB-Verbindungen umzugehen, empfielt sich das Lazy Connecting.
Lazy Connecting bedeutet, dass DB-Verindungen nur dann geöffnet werden, wenn man sie auch wirklich braucht – und zwar so spät wie möglich. Und man braucht die Verbindung eigentlich erst, wenn man auf die Datenbank zugreifen möchte. Nun wäre es aber unglaublich kompliziert, vor jedem mysql_query() erst zu prüfen, ob die DB-verbindung bereits geöffnet ist. Deshalb empfiehlt sich eine eigene Datenbank-Klasse fürs Lazy Connecting.

Diese könnte beispielsweise so (einfach, für mysql) oder so (etwas komplexer, für mysqli) aussehen.
Dadurch werden Verbindungen zur Datenbank auch nur geöffnet, wenn sie wirklich benötigt werden – bzw. wird vor jeder Abfrage geprüft, ob bereits eine Verbindung hergestellt wurde. Effektiverweise würde dann auch in der Wrapper-Funktion für mysql_query die Absicherung per mysql_real_escape_string() erfolgen (oder man nutzt eben PDO, das das über Bind-Parameter selbst übernimmt).