Datenbanken mit MySQL


Eine Datenbank ist eigentlich lediglich eine einzelne Datei, in der viele Daten mit ganz unterschiedlichen Eigenschaften zentral gespeichert und natürlich auch ausgelesen werden können. Okay, das Konzept ist reichlich mit Extras gewürzt, aber bei MySQL beispielsweise kann man die Datenbank-Dateien ohne weiteres ausfindig machen und sich selbst davon überzeugen. MySQL ist ein weitverbreitetes relationales Datenbankverwaltungssystem und wird von PHP nativ unterstützt. Selbstverständlich gibt es Alternativen wie MariaDB, das den Versuch darstellt, ein besseres MySQL zu entwickeln und weitestgehend kompatibel ist, oder MongoDB, das einen nicht-relationalen Ansatz verfolgt und daher zu den NoSQL-Datenbanken gezählt wird. Für typische Anwendungen genügt MySQL jedoch.

Wozu eine Datenbank?


Kann man sich das nicht sparen? Wenn MySQL doch letztlich auch nur mit Wasser kocht (also Dateien zur Speicherung nutzt), warum tun wir das dann nicht auch? Klar, das geht und ist mitunter auch durchaus sinnvoll. Aber MySQL-Datenbanken sind nunmal doch mehr als bloße Dateien und besitzen viele nützliche Features die zum Beispiel den Zugriff auf Daten extrem beschleunigen. In der Regel lässt man daher Webapplikationen alle Daten, die nicht naherliegender Weise als Dateien besser aufgehoben sind (Bilder, ZIP-Archive usw.), in einer Datenbank ablegen.

Was ist SQL?


SQL ist eine Datenbanksprache. So wie wir mit PHP Webanwendungen schreiben können, erlaubt uns SQL einer Datenbank verständlich zu machen, was wir eigentlich von ihr wollen. Eine Datenbank ist ein Container für Tabellen (und noch einiges andere), in denen wir unsere Daten speichern und aus denen wir sie wieder auslesen, wenn uns danach ist. Eine Zeile einer Tabelle nennt man auch einenDatensatz, eine Spalte ein Attribut. Mit SQL schreiben wir nun einen Datensatz in eine Tabelle:
INSERT INTO raumschiffe (name, baujahr, farbe) VALUES ("Sternzerstörer Nr. 367", "A long time ago", "imperial-weiß");

Umgekehrt können wir ihn auch wieder auslesen:
SELECT baujahr, farbe FROM raumschiffe WHERE name = "Sternzerstörer Nr. 367";

SQL ist eine umfangreiche Sprache und der Versuch sie in einem PHP-Grundkurs zu lehren - wär hätte da nicht ein ganz mieses Gefühl? Wir beschränken uns hier auf die absoluten Basics und empfehlen unbedingt eine Vertiefung über diesen Kurs hinaus.

SQL-Piloten-Crashkurs


Wir wir gerade gesehen haben, können wir mit SELECT Datensätze abfragen und mit INSERT schreiben. Fehlt noch UPDATE zum Bearbeiten bereits bestehender Datensaätze und DELETE zum Löschen. Hier ein weiteres Beispiel mit diesen vier Methoden:
INSERT INTO planeten (name, galaxie) VALUES ("Erde", "Milchstraße");
SELECT galaxie FROM planeten WHERE name = "Erde";
UPDATE planeten SET name = "Die blaue Kugel" WHERE name = "Erde";
DELETE FROM planeten WHERE galaxie = "Milchstraße";

Uff! Müssten wir dich nicht schnell ausbilden, damit du bald die Galaxie retten kannst, wären jetzt Ferien angebracht um diesen Informationsüberlauf abzubauen. Vier Zeilen, vier verschiedene Arten von Statements. Wir schreiben SQL-Keywords in Großbuchstaben um sie optisch abzuheben. Das Semikolon am Ende trennt die Statements voneinander. Unglücklicherweise unterscheidet sich die Syntax der verschiedenen Statements deutlich. Eine Alternative zu "Akzeptieren und Auswendiglernen" können wir Dir nicht anbieten.
Der Name unserer Tabelle lautet planeten und sie verfügt über die Attribute name und galaxie. Zunächst fügen wir also mit INSERT INTO einen neuen Datensatz in die Tabelle ein, wobei wir den Namen als "Erde" und die Galaxie als "Milchstraße" angeben. Das legen wir durch den VALUES-Part fest: Er listet die Attribute auf, die wir nachfolgend setzen. Da die Werte Strings sind, umschließen wir sie mit Anführungszeichen. SQL unterstützt verschiedene Datentypen:

  • VARCHAR: Strings mit festgelegter maximaler Länge
  • TEXT: Strings beliebiger Länge
  • INT: Integer
  • TINYINT: Integer mit nur einem Byte, der gerne als Boolean genutzt wird.
  • BOOLEAN: Synonym für TINYINT

Selbstverständlich bietet MySQL auch Datentypen für Fließkommazahlen an sowie Datums- und Zeittypen. Die offizielle Dokumentation verrät die Details. Das Festlegen der Datentypen erfolgt initial beim Erstellen der Tabellen und ist ein Thema für sich.
Doch zurück zu unseren Beispielen. Das zweite Statement fragt mit SELECT einen Datensatz ab. Dabei geben wir die Attribute an, wie wir erhalten möchten, in diesem Fall galaxie. Wir können auch das Wildcard-Zeichen * angeben um pauschal alle Attribute abzufragen. Dabei ist aber zu beachten, dass das ineffizient sein kann, wenn man eigentlich gar nicht alle Attribute benötigt, da dann unnötigerweise Daten von der Datenbank zur PHP-Applikation transportiert werden.
Das SELECT-Statement enthält eine sogenannte WHERE-Klausel. Mit dieser Bedingung wird entschieden, ob ein Datensatz zurückgegeben wird. Das Statement gibt also alle Datensätze zurück, deren Attribut name den Wert Erde angenommen hat. Wir gehen bei diesem Beispiel davon aus, dass es nur einen solchen Datensatz gegen kann. Klingt doch sinnvoll, oder existieren etwa mehrere Planeten mit dem Namen Erde?
Das Attribut name ist daher ein sogenannter Schlüssel. Das beudetet, dass wir über dieses Attribut einen Datensatz eindeutig identifizieren können. Genauer gesagt ist es sogar ein Primärschlüssel, also der Hauptschlüssel. Das ist in dem Fall ersichtlich, weil es gar keinen anderen Schlüssel gibt. Beim Erstellen von Tabellen kann man MySQL anweisen, ein Attribut als Primärschlüssel zu definieren.
Das UPDATE-Statement kommt erneut mit einer anderen Syntax daher. Mit dem Keyword SET legen wir fest, welchen Attribute welche Werte zugewiesen werden sollen. Dabei kann man auch mehrere Zuweisungen - kommasepariert - angeben: SET name = "Mars", galaxie = "Milchstraße" Außerdem treffen wir erneut auf die WHERE-Klausel. Sie wird verwendet um festzulegen, welche Datensätze modifiziert werden sollen. In unserem Beispiel gibt es wie bereits festgestellt nur einen solchen Datensatz, man könnte aber auch mehrere gleichzeitig bearbeiten.
Dir ist sicher bereits klar, dass WHERE-Klauseln im Prinzip den if-Bedingungen aus PHP entsprechen. Daher kann man auch komplexere Ausdrücke bauen. Ein Beispiel: WHERE name != "Erde" AND galaxie = "Milchstraße" Damit fragen wir alle Planeten in der Milchstraße außer unserem Heimatplaneten ab. Wenn du mehr wissen möchtest, empfehlen wir einen Blick in die offizielle Dokumentation.
Falls wir einen Datensatz löschen wollen, stellt uns SQL dafür das DELETE-Statement bereit. Wie gehabt dient eine WHERE-Klausel der Auswahl der zu löschenden Datensätze.
In Bezug auf Tabellennamen und Attribute sollest du noch eine Sache wissen: Man kann sie auch nach SQL-Keywords bennenen. Ein Attribut könnte also where heißen. Damit SQL solche Attributnamen nicht mit Keywords verwechselt, muss man sie besonders kennzeichnen - mit sogenannten Backticks:
SELECT `where` FROM `update` WHERE `delete` = 123

Damit wird das Attribut where aller Datensätze aus der Tabelle update abgefragt, deren Attribut delete den Wert 123 angenommen hat. Es existiert eine Liste der reservierten Begriffe.
Damit wären wir am Ende des SQL-Crashkurses. Themen wie das Anlegen von Tabellen oder die vollständige SELECT-Syntax solltest du dir in Eigenarbeit anschauen.

MySQL in PHP


Jetzt wird's endlich interessant! Vorausgesetzt, wir beherrschen die Basics der Sprache SQL, können wir damit nun in einer PHP-Anwedung mit einer MySQL-Datenbank kommunizieren. PHP stellt dafür nativ drei verschiedene Extensions bereit: mysql, mysqli und PDO. Die mysql-Extension ist veraltet und sollte nicht mehr benutzt werden. Wir schauen uns daher mysqli und PDO an.

mysqli


mysqli ist der Nachfolger der mysql-Extension. Das "i" steht für "improved", also "verbessert". Der erste Schritt ist stets der Kontaktaufbau zur Datenbank. Das ist notwendig, weil MySQLDatenbanken kein Teil unserer PHP-Anwendung sind. Sie laufen in einem eigenen Server-Prozess. Sie können sogar auf einem ganz anderem Server laufen als unsere PHP-Anwendung! (Aus dieser Persepktive ist es erst recht sinnvoll, mit SELECT * sparsam umzugehen und unnötigen Traffic zu vermeiden, oder?!)
mysqli unterstützt sowohl den oldschool prozeduralen Ansatz als auch den modernen objektorientierten. In Anbetracht der Tatsache, dass du dich als Fan einer 1977 initiierten Film-Saga geoutet hast, klingt oldschool möglicherweise gut. Doch hüte dich vor den Verlockungen der dunklen Seite! Wir helfen dir dabei und geben den Weg der Objektorientierung vor. Falls du darin noch ungeübt bist, bieten wir dir gerne unser Wissen darüber in einem eigenen Kapitel an.

Verbindung aufbauen


Damit deine Webapplikation die Verbindung zu einer MySQL-Datenbank aufbauen kann, benötigt sie die Anmeldeinformationen. Diese legst du beim Erstellen der Datenbank fest oder sie werden dir von deinem Hoster mitgeteilt.
$mysqli = new mysqli('hostname', 'username', 'password', 'databasename');

Mit new mysqli bauen wir eine Verbindung auf. Der Konstruktor-Methode übergeben wir die Anmeldedaten. hostname ist dabei die Identifikation des MySQL-Servers. Läuft dieser auf dem gleichen Root- oder Virtual Server wie PHP, dann genügt in der Regel die Angabe von localhost (oder 127.0.0.1). Andernfalls muss meist eine IP, manchmal mit Angabe eine Ports, übergeben werden - wie im folgenden Beispiel:
$mysqli = new mysqli('12.34.56.78', 'luke', 'red5', 'secretdatabase', 1234);

Eine MySQL-Datenbank unterstützt das Konzept von Benutzern. Daher muss es zu jeder Datenbank mindestens einen Benutzer geben, der ein eigenes Passwort besitzt. In diesem Beispiel heißt der Benutzer luke und hat das Passwort red5. Nicht sehr sicher, aber nun denn. Sobald die Anmeldung an die Datenbank erfolgt ist, kannst du das Benutzer-Konzept ignorieren, sofern du das möchtest.
Ob die Anmeldung erfolgreich war, kannst du ganz einfach dadurch feststellen, dass $mysql->connect_errno nur in diesem Fall nicht gleich 0 ist:
if ($mysqli->connect_errno > 0) {
die('Verbindung schlug aus diesem Grund fehl: '.$mysqli->connect_error);
}

connect_errno gibt also die Fehlernummer an, connect_error die Fehlerbeschreibung.

Statements ausführen


Gelingt der Aufbau der Verbindung, können wir nun endlich SQL-Satements (Queries) an unsere Datenbank schicken. Das folgende Beispiel erzeugt zunächst eine Tabelle. Alternativ kann man zum Bearbeiten der Struktur Tools wie phpMyAdmin oder das offizielle MySQL Workbench verwenden. Das zweite Statement fügt der Tabelle einen Datensatz hinzu.
$mysqli->query('CREATE TABLE raumschiffe (name VARCHAR(255), baujahr INT, PRIMARY KEY (name))');
$mysqli->query('INSERT INTO raumschiffe (name, baujahr) VALUES("Rasender Falke", "1977")');

Vorhin haben wir SQL-Statements mit einem Semikolon abgeschlossen, das müssen wir nun nicht mehr tun, da wir mit der query-Methode ohnehin nur ein einzelnes Statement abschicken dürfen.

Bei der Abfrage von Daten wird es nun wieder spannend. Wie ein entsprechendes SQL-Statement aussehen kann wissen wir bereits, aber wie gehen wir mit dem um, was uns die Datenbank schickt? Das geht beispielsweise so:
$result = $mysqli->query('SELECT name FROM raumschiffe WHERE baujahr = 1977');

while ($row = $result->fetch_assoc()) {
echo(' name: '.$row);
}

PHP ist an dieser Stelle etwas umständlich. $result ist nicht das Ergebnis, sondern ein Objekt zum Zugriff auf das Ergebnis, genauer gesagt ein Objekt der Klasse mysqli_result. Es stellt die Methode fetch_assoc() bereit. Wird diese aufgerufen, liefert sie den "nächsten" Datensatz in Form eines assoziativen Arrays zurück. Dabei sind die Keys des Arrays die Attributnamen und die Values die Attributwerte. Da fetch_assoc() nur einen Datensatz zurückgibt, muss man es so lange aufrufen, bis es null zurückgibt, wenn man alle zurückgelieferten Datensätze abfragen will - dazu dient die while-Schleife. Sie speichert zunächst den nächsten Datensatz in der Variable $row (zu deutsch "Zeile") und führt dann solange den Code in ihrem Körper aus, wie $row nicht null ist. Natürlich kann man das auch anders lösen, dies ist aber einer sehr kurze Schreibweise.
Ob und wenn ja wie viele Datensätze überhaupt gefunden wurden kann man der Eigenschaft num_rows entnehmen:
$count = $result->num_rows;

Last Inserted ID


Die Tabelle raumschiffe hat ein Problem: Schiffe benötigen einen eindeutigen Namen. In der gesamten bekannten Galaxie kann es also nur einen Rasenden Falken geben. Schön wär's, aber mal ehrlich, würden wir nicht alle unser Raumschiff gerne so nennen? Daher führt man in der Praxis oft ein zusätzliches Attribut namens id (eben zum Identifizieren) ein, das dann der Primärschlüssel ist:
... id INT AUTO_INCREMENT, PRIMARY KEY (id)

Der Constraint (eine Bedingung) AUTO_INCREMENT erlaubt es MySQL, die ID automatisch zu vergeben - sie wird einfach um eins höher als die bis dato höchste ID gesetzt. Das Einfügen eines neuen Datensatzes funkioniert dann genau wie bereits gezeigt, für die ID muss kein Wert angegeben werden. Wenn man nun wissen will, welche ID MySQL dem Datensatz vergeben hat, kann man das wie folgt abfragen:
$mysqli->query('INSERT INTO ...');
echo 'Diese ID wurde vergben: '.$mysqli->insert_id;

comments powered by Disqus

© 2014-2017 Christoph Konnertz.