← Journal · Archiv

Lost Connection during query

September 05, 2006

In letzter Zeit lasse ich meinen Blog etwas schleifen. Das hat wie immer seine Gründe. Neben meinen operativen Tätigkeiten bei mySniper.com, diversen neuen Features wie dem SMS-Versand usw., habe ich noch vier(!) weitere Projekte am Laufen oder in Planung, die natürlich meine Arbeit bei meinem neuen Arbeitgeber Zeta Software nicht beeinträchtigen sollten. Über meine Arbeit bei Zeta werdet ihr bald mehr erfahren, denn dort lerne ich jeden Tag einiges dazu, dass euch sicher auch interessiert.
Bei einem meiner eigenen Projekte nutze ich u. a. die neuen Major-Versionen des MySQL-Servers und PHP. Dabei stolpere ich ab und an über einige Bugs oder etwas unausgeklügelte »Features«.

It doesn’t called »bleeding edge« for nothing

So verwende ich Stored Procedures um über einen FULLTEXT-Index aus ISAM-Tabellen zu lesen. Das klappt ganz gut, nur das jede dritte oder vierte Abfrage über ein und die selbe Connection zu einer Fehlermeldung führt:

Lost connection to MySQL server during query

Zunächst dachte ich an einen Bug, da der Fehler nicht immer auftrat. Ohne Stored Procedure funtionierte die Abfrage ohne Probleme. Nur sobald eine Stored Procedure ins Spiel kam, hängte sich manchmal die Verbindung auf.
Das Problem trat nur bei mysqli von PHP 5 auf. Über den mysql-Client funktionierte der Aufruf der Stored Procedure einwandfrei.
Der Schlüssel zum ganzen ist wohl, dass man für Stored Procedures die mysqli-Funktion multi_query() verwenden muss und nicht query().

if ($database->multi_query("CALL GetNewItems();")) {
  if ($items = $database->store_result()) {
    while($item = $items->fetch_array(MYSQLI_ASSOC)) {
      printf("%s", $item["title"]);
    }
    $items->close;
  }

  do {
    # Throw pending results away
  } while ($database->next_result());
}

multi_query() verwendet man eigentlich, wenn man mehrere Result-Sets aus einem Query geliefert bekommt. Ungefähr so:

SELECT * FROM items; SELECT * FROM parents;

Diese Result-Sets kann man dann mit next_result() in einer Schleife durcharbeiten. Eine Stored Procedure liefert beim MySQL-Server 5 u. U. ein zweites Result-Set, was das mysqli-Interface wohl dazu bewegt bei unbehandelten Result-Sets, die Verbindung bei einem weiteren Query zu schließen.
Weiß der Teufel warum!
Da das zweite Result-Set in meiner Stored Procedure sowieso leer ist und ich auch nur eines erwarte, werfe ich es mit der Schleife am Ende meines Beispielcodes weg. Danach kann ich einen weiteren Query absetzen.
Laut Bug-System und Dokumentation von PHP ist dass ein absolut normales Verhalten von mysqli.

6 Kommentare

Peter ·

“Eine Stored Procedure liefert beim MySQL-Server 5 u. U. ein zweites Result-Set”

Und genau hier liegt meiner Meinung nach der Bug. Wieso liefert eine Prozedur teilweise ein “leeres” Resultset mit? Wenn es nur ab und zu vorkommt, dann ist es definitiv ein Bug.

Ich hatte mal ein ähnliches Problem. Allerdings lag der Fehler damals bei mir. Ich hatte eine sehr umfangreiche Prozedur und an einer Stelle hatte ich ein “verwaistes” SELECT-Statement, welches mir dann klammheimlich noch ein Resultset zurückgegeben hat.

lemming ·

Die Version 5 ist sowieso nicht sehr stabil. Ist nur ein Beispiel das mich Zeit gekostet hat.
Hey aber dafür kenne ich mich jetzt Optitofi mit den Internas des MySQL-Servers aus.
Was war bei dir das Problem, Peter?

Peter ·

Wie gesagt, ich hatte bei mir im Code noch ein ziemlich sinnloses SELECT-Statement (”leere” Rückgabe), welches ich vergessen hatte zu löschen. Danach kam der eigentliche Code, der mehrere Resultset zurückgeben sollte.

Das Problem war, dass das erste Statement immer ein leeres Resultset geliefert hat. Erst die folgenden Statements brachten dann das erwartete Ergebnis.
Damals dachte ich auch, dass der SQL-Server buggy ist und per Standard erst mal ein leeres Resultset liefert. Erst später ist mir das dämliche SELECT-Statement aufgefallen. Mittlerweile versuche ich, per Prozedur nur jeweils ein Resultset zu erzeugen und damit die Prozeduren funktional voneinander zu trennen. Ist für mich persönlich übersichtlicher.

yummycandy ·

Lemming, hast du dir schon einmal PDO angeschaut? Ich finde das persönlich performanter und durchdachter als alle anderen DB-Implementierungen in PHP5. Der Umstieg von ADO.NET zu PDO ist relativ einfach, außerdem lässt sich damit ein prima DAL bauen.

lemming ·

PDO sieht wirklich interessant aus. Vorallem die Verwendung von Exceptions erspart gewaltigen Programmieraufwand.

Bei meinen zukünftigen Projekten wird es aber egal sein, welche Basis meine Datenbankverbindung hat, da ich, wie mein Programmierkollege in der Firma, die Records in einer Datenbank als Instanzen von selbst geschriebenen Datenbankobjekten behandeln werde.

Das hat sich hier ziemlich gut bewährt.

lemming ·

Btw. allerschärfstes Willkommen, yummycandy.

Kommentar hinterlassen