MB: Connection zur SQL Datenbank aufwändig?

Moin Community,

  1. Sollte man Try-Catch-Blöcke bei jeder Aktion auf die Databank machen? Mit einer Aktion meine ich: prepare(), execute(), setAttribute(), fetch()!

  2. Was ist der Unterschied zwischen fetchAll() und fetch() in while-Loop Condition Konstruktion?

  3. warum sollte man exec(), und query() in kombination mit fetch-Arten verwenden? Wenns auch nur eine einfacher SELECT-Befehl ist ohne nennenswerte Variablen.

  4. Ich habe eine Datnbank klasse entwickelt. Bevor eine Datenbank Aktion in der Klasse stattfinden, muss erst die gespeicherten Attribute geladen werden:

  • $db->connect() für die Erzeugung des PDO-Objekts die bei der Instanziierung speichert wurden,
  • die gesetzten PDO Attribute aus einem asoziativem Array $db->getAttribute()
  • schluss entlich nach der Aktion muss das ganze abgebaut werden mit $db->disconnect().

viel zu viel aufwand? leidet die perfomance sehr darunter alles wieder aufzubauen? sollte man die Connection bestehen lassen?

vlg MB

akzeptierte Antworten

  1. Tach!

    1. Sollte man Try-Catch-Blöcke bei jeder Aktion auf die Databank machen? Ene Aktion meine ich prepare(), execute(), setAttribute(), fetch())?

    Es empfiehlt sich überall da, wo Fehler auftreten können, mit ihnen zu rechnen und eine Behandlung einzubauen. Bei voneinander abhängigen Geschichten ist es wenig sinnvoll, jede einzelne in ein eigenes try-catch einzurahmen, weil man ja beim Auftreten eines Fehler sowieso nicht fortfahren kann.

    1. Was ist der Unterschied zwischen fetchAll() und fetch() in while-Loop Condition Konstruktion?

    Kommt drauf an, was du damit machst. Willst du nur ein Array zurückgeben, dann fetchAll(), willst du jeden Datensatz behandeln, dann kannst du auch fetchAll() in einer foreach-Schleife laufen lassen, oder die while-mit-fetch-Schleife nehmen.

    Eigentlich ist es weniger ressourcenhungrig, wenn man die Datensätze einzeln bearbeitet als ein großes Array mit allen aufzubauen. Das spielt aber bei den MySQL-Extensions in PHP keine Rolle, weil die sowieso die gesamte Datenmenge im Hintergrund bereits abgeholt haben und zwischenspeichern. Das Fetchen greift nur noch auf diesen Zwischenspeicher zu. Das Verhalten kann man umschalten (buffered oder unbuffered Query). Meist sind die Datenmengen für Webseiten so gering, dass der höhere Speicherverbauch nicht ins Gewicht fällt.

    1. warum sollte man exec(), und query() in kombination mit fetch-Arten verwenden? Wenns auch nur eine einfacher SELECT-Befehl ist ohne nennenswerte Variablen.

    Nimm das was du für richtig hältst. Aber beachte, dass deine Statements syntaktisch korrekt werden. Also dass alle eingefügten Daten korrekt maskiert werden.

    viel zu viel aufwand? leidet die perfomance sehr darunter alles wieder aufzubauen? sollte man die Connection bestehen lassen?

    Ja. Die Sache mit der Performance kannst du ja messen, ob das in deinem Fall spürbare Auswirkungen hat. Die Connection für jede Query neu zu erstellen bleibt unabhängig von der Geschwindigkeit aber für eine hintereinander abgearbeitete Webseite sinnlos, wenn es dafür keinen technischen Grund gibt. Anders sähe das bei Desktop-Anwendungen aus, wo nur gelegentlich mit Pausen dazwischen eine Query abgesetzt wird.

    dedlfix.

    1. Tach!

      1. Sollte man Try-Catch-Blöcke bei jeder Aktion auf die Databank machen? Ene Aktion meine ich prepare(), execute(), setAttribute(), fetch())?

      Es empfiehlt sich überall da, wo Fehler auftreten können, mit ihnen zu rechnen und eine Behandlung einzubauen. Bei voneinander abhängigen Geschichten ist es wenig sinnvoll, jede einzelne in ein eigenes try-catch einzurahmen, weil man ja beim Auftreten eines Fehler sowieso nicht fortfahren kann.

      Nachtrag: Die Frage ist dabei, wo man am besten die Behandlung einbaut. Das geht einher mit der Frage, was man im Falle eines Falles zu tun gedenkt. Prinzipiell kann der Code, der die Datenbankabfrage durchführt, die Exception fangen. Aber was macht er dann damit? Der soll sich um die Datenbankabfrage kümmern und keine Ahnung von der Ausgabe haben. Also sollte der Code auch keine Ausgabe produzieren. Das Programm per die() abbrechen soll er auch nicht, weil die Prgrammablaufsteuerung nicht zu seinen Aufgeben gehört. Kann er dann überhaupt was sinnvolles mit der Exception machen, als sie nur an den Aufrufer durchzureichen, damit der sich angemessen darum kümmern kann? Der Aufrufer muss ja wissen, warum er die Daten braucht und was er zu tun gedenkt, wenn er keine bekommt. Das liefe dann darauf hinaus, dass man die Exception lediglich fängt und neu wirft.

      Man könnte als Aufgabe sehen, dass die Exception geloggt wird, bevor sie erneut in Richtung Aufrufer geworfen wird. Aber warum sollte sich der Datenbank-Code darum kümmern? Der muss nicht wissen, welches Logging-Management der Verwender benutzt.

      Gegebenenfalls kann man die Exception ändern, wenn man dafür einen Grund findet, oder ein weiteres Exception-Objekt erstellen mit der ursprünglichen als Previous Exception. Sowas kann man machen, wenn man die Exceptions verschiedener Datenbanktreiber vereinheitlichen möchte. Also wenn man eine zusammenfassende DBException statt MysqlException nebst PostgresException nebst OracleException oder dem zu allgemeinen Objekt der Klasse Exception haben möchte, falls man gedenkt, all diese DBMSe zu unterstützen (jetzt mal so als Beispiel gesagt, unabhängig davon, ob die entsprechenden Treiber Exceptions werfen oder nicht).

      dedlfix.

  2. Hi,

    Setze im PDO ERRMODE_EXCEPTION und schleife die Fehlermeldung (Exception chaining). Aufgefangen wird zum Schluss, also nur ein try/catch Block beim Zusammenbau der Antwortseite. D.h., wenn irgendwo beim Zusammenstellen einer bliebigen Response eine Exception fällt, fängt das Dein Framework auf.

    MfG

  3. Hallo MB,

    den Overhead für den Connection-Aufbau kannst Du mit persistenten Connections (ATTR_PERSISTENT beim new PDO) beseitigen. Dann bleiben die Connections mit gleichem User/Passwort unter der Haube geöffnet und werden wiederverwendet.

    Nachteil 1: Wenn Du Connection-Eigenschaften setzt, bleiben die dran (also sparsam tun und konsistent tun)

    Nachteil 2: Wenn eine schlummernde Connection lange liegt, kann der Server sie schließen und man kann eine Exception bei der Wiederverwendung bekommen. Das kann insbesondere bei einer geclusterten DB passieren; ich habe da mit .net und MS SQL Server schon böse Erfahrungen gemacht. Ob MYSql oder PDO das unter der Haube abfangen, weiß ich nicht. D.h. du müsstest das beim Connect erkennen und einen Retry machen.

    Rolf

    --
    Dosen sind silbern
    1. Tach!

      den Overhead für den Connection-Aufbau kannst Du mit persistenten Connections (ATTR_PERSISTENT beim new PDO) beseitigen. Dann bleiben die Connections mit gleichem User/Passwort unter der Haube geöffnet und werden wiederverwendet.

      Klingt gut, wenn man das so liest. Dazu muss man aber eine Menge beachten. Damit Connections aufbewahrt werden können, muss irgendwas laufen, um sie zu verwalten. Das geht mit PHP als Apache-Modul, aber nicht, wenn es als CGI läuft und deswegen für jeden Request neu gestartet und beendet wird. Okay, das reine CGI nimmt man heutzutage nicht mehr, inwieweit aber FCGI und FPM dazu in der Lage sind, entzieht sich meiner Kenntnis.

      Das PHP-Handbuch hat dazu Hinweise auf Lager: The mysqli Extension and Persistent Connections. Auch der alte mysql-Treiber wies auf zu beachtende Probleme hin: mysql_pconnect

      Wenn man persistente Connections verwenden möchte, muss das also mit der Konfiguration des Datenbankservers abgestimmt sein. Und die Verwender müssen sicherstellen, dass sie keine unsauberen Verbindungen hinterlassen. Ich würde persistente Connections lediglich als Option anbieten, wenn überhaupt. Der Verbindungsaufbau zu MySQL geht sehr schnell, so dass man den Unterschied wohl eher kaum spüren wird.

      dedlfix.