Datenbankzugriff mit Perl

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Hidiho,

    man kennt es ja. Man möchte ein Addon bauene, welches mit Datenbanken arbeitet (beispielsweise Gästebücher, Integration etc.) oder gar die Umsetzung einer Datenbankanbindung für den Chat. Dazu gibts hier mal nen Tutorial. Mal schauen, wer zuerst etwas daraus macht :) Dank geht an artemis_TOAO.


    DBI ist Perls Schnittstelle für die Datenbankbenutzung. Die Schnittstelle ist Datenbank unabhängig und kann mit den meissten gängigen Datenbanken auf die gleiche Art benutzt werden - MySQL, mSQL, PostgreSQL, CSV Dateien, Oracle, Access usw. Die Schnittstelle ist immer die gleiche, nur der im Hintergrund benutzte Treiber ändert sich.

    Inhalt
    0. DBI einbinden
    1. Verbindung herstellen
    2. Verbindung trennen
    3. Mit der Datenbank arbeiten
    a) Grundlegendes
    b) INSERT, UPDATE, DELETE (,DROP, ALTER, ...)
    c) Alle Datensätze zurückliefern
    d) Abfragen mit nur einem Datensatz
    e) Abfragen mit Parametern
    f) Die quote-Methode
    4. Weiterführende Funktionen
    a) Ausgabevariablen
    b) Zugriff auf den gesamten Datensatz ohne prepare/execute
    c) Auto Commit und Raise Error
    d) Transaktionen
    5. Bücher(tipps)


    0) DBI einbinden
    Das DBI Modul wird ganz normal per use eingebunden und sollte standardmäßig auf jedem Webspace mit Perl Unterstützung installiert sein:

    Quellcode

    1. use DBI;



    1) Verbindung herstellen
    Der erste Schritt in Richtung Datenbankbenutzung mit Perl ist das erstellen eines Datenbank Handles. Um dieses Handle zu erzeugen benötigen wir drei Informationen, der Datenbankdialekt, der Benutzername und das Passwort.
    In dem Tutorial gehe konkret nur auf den Gebrauch von MySQL ein. Als Beispiel verbinden wir zu der MySQL Datenbank 'test' mit dem Benutzernamen 'root' und dem Passwort 'pw':

    Quellcode

    1. my $dbh = DBI->connect("DBI:mysql:test",'root','pw');



    Es sind natürlich auch mehrere gleichzeitige Verbindungen zu verschiedenen Datenbanken möglich:

    Quellcode

    1. my $dbh1 = DBI->connect("DBI:mysql:test1",'root','pw');
    2. my $dbh2 = DBI->connect("DBI:mysql:test2",'root','pw');



    Sicherheitshalber können wir noch das Script beenden falls die Verbindung fehl schlägt:

    Quellcode

    1. my $dbh = DBI->connect("DBI:mysql:test",'root','pw') or die "connection failed $DBI::errstr";



    Hier lernen wir auch direkt die nächste Funktion kennen: $DBI::errstr, diese Funktion ist nicht an ein Objekt gebunden, sondern gibt den letzten Fehler aus dem DBI Package zurück. Analog arbeitet die Funktion err aus dem DBI Package (hier $DBI::err), diese gibt die Fehlernummer zurück.

    Eine Liste der installierten Treiber kann man sich vorneweg mit der Funktion available_drivers ausgeben lassen, im Arraykontext liefert die Funktion einen Array mit den installierten Treibern zurück. Diese Funktion hat keinen direkten Nutzen für die Programme aber vielleicht ist es interessant zu wissen welche Treiber installiert sind:

    Quellcode

    1. my @drivers = DBI->available_drivers;



    2) Verbindung trennen
    Wir haben nun eine Verbindung zur Datenbank, manchmal müssen wir aber auch eine Verbindung trennen.

    Quellcode

    1. $dbh->disconnect;



    3) Mit der Datenbank arbeiten
    a) Grundlegendes

    Mit DBI ist das Arbeiten mit einer Datenbank in mehrere Schritte unterteilt:
    1. vorbereiten des Statements (prepare)
    2. ausführen (execute)
    und 3. das verarbeiten der Informationen (fetch)

    zu 1.: Die prepare Methode des Datenbank Handles liefert ein neues Objekt für diese Abfrage zurück (wenn die Anfrage korrekt ist).
    zu 2.: Das Ausführen geschieht über die execute Methode des zurückgelieferten Objekts
    zu 3.: Hier gibt es viele Möglichkeiten, für das erste gehe ich hier nur auf die 3 typischsten Funktionen ein: fetchrow_array, fetchrow_arrayref sowie fetchrow_hashref

    Als Beispiel selektieren wir alle Felder der Tabelle 'testtabelle' und geben je einen Datensatz mit jeder der vier Methoden aus:

    Perl-Quellcode

    1. #!/usr/bin/perl
    2. # einbinden des DBI packagaes
    3. use DBI;
    4. my $dbh = DBI->connect("DBI:mysql:jt",'root','') or die "connection failed $DBI::errstr";
    5. my $query = $dbh->prepare('SELECT * FROM testtabelle');
    6. # ausführen
    7. $query->execute;
    8. # eine Zeile mit fetchrow_array auswählen
    9. my @data = $query->fetchrow_array;
    10. # ausgabe des zweiten Elements
    11. print @data[1];
    12. # das gleiche mit fetchrow_arrayref
    13. my $data = $query->fetchrow_arrayref;
    14. print @$data[1];
    15. # und das ganze als hashref
    16. # (hier kein my, da es das skalare $data im Namensraum schon gibt)
    17. my $data = $query->fetchrow_hashref;
    18. print $$data{'zweitesfeld'};



    Um alle Datensätze nacheinander zu bearbeiten, bietet sich der Gebrauch in einer WHILE Schleife an:

    Quellcode

    1. # ...
    2. my $query = $dbh->prepare('SELECT * FROM testtabelle');
    3. # ausführen
    4. $query->execute;
    5. # alle datensätze durchlaufen und jeweils das feld 'zweitesfeld' ausgeben
    6. while(my $data = $query->fetchrow_hashref) {
    7. print $$data{'zweitesfeld'};



    In gute Perl Art kann man bei Rückgabe eines - richtigen - Arrays, dessen Elemente direkt Variablen zuordnen:

    Quellcode

    1. while(my ($id,$zweitesfeld) = $query->fetchrow_array()) {
    2. print "$id - $zweitesfeld\n";
    3. }



    Mit der Methode finish kann man direkt zum Ende der Datensätze springen (hinter den letzten).

    b) INSERT, UPDATE, DELETE (,DROP, ALTER, ...)
    Abfragen, die keine Datensätze zurückliefern und daher nur ausgeführt werden müssen können direkt mit der Funktion do abgesetzt werden, der Rückgabewert ist bei einer erfolgreichen Ausführung die Anzahl der betroffenen Zeilen und bei einem Misserfolg 'undef':

    Quellcode

    1. $dbh->do('DELETE FROM eineTabelle WHERE id=3');



    c) Alle Datensätze zurückliefern
    Man kann sich selbstverständlich auch direkt alle Datensätzen zurückliefern lassen. Dafür gibt es die Funktion selectall_arrayref. Die Funktion gibt eine Referenz auf einen Array zurück, die wiederrum Referenzen zu allen Ergebnissen enthält. Ein Beispiel:

    Quellcode

    1. # ...
    2. my $query = $dbh->prepare('SELECT * FROM testtabelle');
    3. # ausführen
    4. $query->execute;
    5. # eine array referenz, die array referenzen auf alle ergebnisse enthält
    6. my $data = $query->fetchall_arrayref;
    7. # durchlaufen des arrays und ausgabe des jeweils zweiten feldes
    8. foreach my $array (@$data) {
    9. print @$array[1];
    10. }



    d) Abfragen mit nur einem Datensatz
    Benötigt man nur einen Datensatz, beispielsweise Zählen von bestimmten Datensätzen oder die Auswahl eines ganz bestimmten Datensatzes, kann man die Methoden selectrow_hashref oder selectrow_arrayref des Datenbank Handles benutzen (je nachdem ob man lieder die schnelleren Hashs oder geordneten Arrays benutzt),
    Die beiden Funktionen liefern eine Referenz auf den Ergebnishash bzw - array zurück die dritte einen 'echten' Array. Beide benötigen als Parameter das auszuführende Statement. Anbei ein Beispiel mit einer Hashreferenz:

    Perl-Quellcode

    1. #!/usr/bin/perl
    2. # einbinden des DBI packagaes
    3. use DBI;
    4. # verbinden
    5. my $dbh = DBI->connect("DBI:mysql:jt",'root','') or die "connection failed $DBI::errstr";
    6. # die funktion führt das query aus und gibt den ersten datensatz zurück
    7. my $data = $dbh->selectrow_hashref('SELECT * FROM testtabelle');
    8. print $$data{'zweitesfeld'};



    e) Abfragen mit Parametern
    Nach den trivialen Möglichkeiten des DBI Moduls kommen wir nun zu einem interessanten Thema, Abfragen mit Platzhaltern. In einer Abfrage können Platzhalter durch '?' definiert und erst später eingesetzt werden. Dadurch muss die Abfrage nur einmal in der Datenbank (und natürlich in dem Modul) vorbereitet werden muss - sehr hilfreich wenn viele Einträge geändert oder eingefügt werden müssen. Neben dem Geschwindigkeitsvorteil gibt es einen weiteren netten Nebeneffekt, die Werte der Parameter werden direkt escaped, das heisst alle Sonderzeichen werden entschärft.
    Nach dem Vorbereiten des Statements mit Platzhaltern, kann man Parameter mit der bind_param Methode hinzufügen. Sind alle Parameter hinzugefügt kann das Statement mittels execute ausgeführt werden, danach neue Parameter, wiederholtes ausführen, neue Parameter usw.
    Die Parameter sind von 1 an durchnummeriert. Hier ein Beispiel:

    Perl-Quellcode

    1. #!/usr/bin/perl
    2. # einbinden des DBI packagaes
    3. use DBI;
    4. # verbinden
    5. my $dbh = DBI->connect("DBI:mysql:jt",'root','') or die "connection failed $DBI::errstr";
    6. $query = $dbh->prepare("INSERT INTO testtabelle (id,zweitesfeld) VALUES (?,?)");
    7. # die parameter sind von 1 an durchnummeriert
    8. $query->bind_param(1,4);
    9. $query->bind_param(2,'wert1');
    10. $query->execute;
    11. $query->bind_param(1,5);
    12. $query->bind_param(2,'wert2');
    13. $query->execute;



    Man kann die Parameter auch der Reihenfolge nach direkt in der execute Methode angeben, das ist kürzer aber auch unübersichtlicher:

    Quellcode

    1. $query->execute(44,'einwert');



    Wenn ein Parameter hinzugefügt wird versucht die Methode bind_param automatisch den Typ des Wertes zu bestimmen. Man kann aber auch direkt den Typ als optionalen Parameter angeben. Der optionale dritte Parameter ist eine Typbezeichnung aus dem DBI Modul:

    Quellcode

    1. $query->bind_param(1,'einstring',DBI::SQL_VARCHAR);



    Analog geht dies für alle anderen Typen (SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE, SQL_DATE, SQL_TIME, SQL_TIMESTAMP, SQL_VARCHAR, SQL_LONGVARCHAR, SQL_BINARY, SQL_VARBINARY, SQL_LONGVARBINARY, SQL_BIGINT, SQL_TINYINT, SQL_BIT, SQL_WCHAR, SQL_WVARCHAR, SQL_WLONGVARCHAR)

    f) Die quote-Methode
    Die quote Methode des Query Objekts entfernt die spezielle Bedeutung aller Sonderzeichen anhand des gewählten Treibers, zum Beispiel für Benutzereingaben. Der Parameter und Rückgabewert sind jeweils ein String.

    4. Weiterführende Funktionen

    Eigentlich könnten wir hier schon aufhören, wir haben mehr als alle notwendigen Funktionen und Möglichkeiten besprochen aber es gibt noch weitere, nicht umbedingt notwendige aber hilfreiche, Funktionen:

    a) Ausgabevariablen
    Statt dem Zugriff über Referenzen oder Arrays und Hashs kann man auch Variablen definieren, die dann bei jedem Schleifendurchlauf automatisch aktualisiert werden. Bei einer sinnvollen Namensgebung erhöht dies auf der einen Seite die Lesbarkeit und Verständlichkeit des Codes erheblich und auf der Anderen ist der Zugriff übersichtlicher:
    Die Zuordnung erfolgt mittels Nummerierung der Spalten, beginnend bei 1.

    Perl-Quellcode

    1. #!/usr/bin/perl
    2. # einbinden des DBI packagaes
    3. use DBI;
    4. # verbinden
    5. my $dbh = DBI->connect("DBI:mysql:jt",'root','') or die "connection failed $DBI::errstr";
    6. $query = $dbh->prepare('SELECT * FROM testtabelle');
    7. $query->execute;
    8. # in dem namensraum deklarieren
    9. my ($id, $zweitesfeld);
    10. # binden der variablen an die felder
    11. $query->bind_col(1,\$id);
    12. $query->bind_col(2,\$zweitesfeld);
    13. # ausgabe
    14. while($query->fetch) {
    15. print "$id - $zweitesfeld\n";
    16. }



    Es müssen nicht alle Spalten gebunden werden, ein Vorwissen über die Struktur der Tabelle ist aber offensichtlich zwingend nötig.

    b) Zugriff auf den gesamten Datensatz ohne prepare/execute
    Unter Punkt 3c) besprachen wir, wie man alle Datensätze eines vorbereiteten Statements erhält. Es gibt auch eine äquivalente Methode des Datenbank Handles, ohne prepare und execute. Die Methode heisst nach gute Tradition selectrow_arrayref.

    Quellcode

    1. # ...
    2. my $data = $dbh->selectall_arrayref('SELECT * FROM testtabelle');
    3. foreach my $array (@$data) {
    4. print @$array[1];
    5. }



    c) Auto Commit und Raise Error

    Quellcode

    1. $dbh->{'AutoCommit'};



    enthält den boolean Wert, ob auto Commit aktiviert ist oder nicht. Den Wert kann man einfach per direktem Zugriff auf das Attribut verändern:

    Quellcode

    1. $dbh->{'AutoCommit'} = 1;



    Quellcode

    1. $dbh->{'RaiseError'};

    enthält den Wert des Raise Error Attributs und kann auf die gleiche Weise verändert werden:

    Quellcode

    1. $dbh->{'RaiseError'} = 1;



    . Bei Benutzung dieses Attributs muss man aber Bedenken, dass manche Fehler mittels 'die' ausgelöst werden und somit durch dieses Attribut nicht entschärft werden. Um ganz sicher zu gehen sollte man nicht auf die gewohnte Fehlerbehandlung verzichten.

    Alternativ kann man die Attribute auch beim Verbinden zur Datenbank als optionalen Hash als letzten Parameter angeben:

    Quellcode

    1. my $dbh = DBI->connect("DBI:mysql:jt",'root','', {'AutoCommit' => 1, 'RaiseError' => 0})



    d) Transaktionen
    Abschliessend erwähne ich noch kurz die Unterstützung von Transaktionen - Transaktionen ansich zu erklären wäre hier sicherlich zuviel. Es gibt hier zwei elementare Methoden des Datenbank Handles: commit und rollback. commit führt die angesammelten Änderungen aus und rollback widerruft alle Änderungen bis zum letzten commit. Offensichtlich ist der Einsatz von commit und rollback in Kombination mit AutoCommit sinnfrei.
    Ob Transaktionen unterstützt werden hängt insbesondere direkt von dem Datenbanktreiber ab, werden keine Transaktionen unterstützt enstpricht das dem Verhalten von AutoCommit oder einem commit nach jeder Änderung.

    5. Bücher(tipps)
    O'Reilly - Programming the Perl DBI
    O'Reilly - Programming Perl

    Viel Spaß damit.

    Und nochwas natürlich:
    Ich übernehme keine Haftung falls dieses Script Schäden an eurem Chat hervorrufen sollte! Macht am besten vorher ein Backup aller Dateien!

    1.448 mal gelesen