Software-Engineering Martin Fabiani

Sitemap (Navigation ohne JavaScript)

Impressum: Martin Fabiani, Röderbergweg 104, D-60485 Frankfurt, Tel: +49 (69) 49084808, E-Mail: info (at) fabiani.net, USt-IdNr: DE217298609

Tips und Tricks zu Perl

MySql-Datenbankzugriff via DBI

Da im Forum von perl-community.de häufig Fragen zum Zugriff mit Perl ueber DBI und DBD::mysql kommen, versuche ich hier die wichtigsten Grundregeln zu erklären.

(Bei den folgenden Code-Beispielen gehe ich davon aus, daß der Server myserver, die Datenbank mydb, der zugreifende Benutzer myuser heißt und das Passwort geheim.)

  1. Von wo bekomme ich Informationen zu DBI und mysql?

  2. Wie stelle ich eine Verbindung zur Datenbank auf meinem MySql-Server her?
    #! /usr/bin/perl
    use warnings;	  
    use strict;
    
    use DBI; # laden des DBI-Moduls
    
    my $dsn = 'DBI:mysql:mydb:myserver';  # datasourcename:  wenn myserver weggelassen wird,
                                 # wird standardmäßig localhost verwendet. 
    my $attributes = { PrintError => 0, RaiseError => 0 }; # siehe Doku zu DBI
    
    my $dbh = DBI->connect($dsn, 'myuser', 'geheim', $attributes)
      or &WriteError('', "Error in connecting to $dsn", die => 1); 
      # immer Returncodes und Fehler auswerten!!!
     
    # --- Fehlerbehandlungsroutine
    sub WriteError {
       my ($dbh, $message, %action) = @_;
        
       if( $action{die} ) {
         die "$message:\n  $DBI::err ($DBI::errstr)\n";
       }
       else {
         warn "$message:\n  $DBI::err ($DBI::errstr)\n";
       }
    
       # bei CGI-Scripten sollte man wahrscheinlich die...; durch print ...; exit; 
       # ersetzen, und warn...; durch ein normales print ... ohne exit, weil bei 
       # den meisten Webservern ein 500er Fehler kommt, wenn das Script Text auf STDERR 
       # ausgibt und das Webserver-Log zugemüllt wird. Als Alternative kann man für die
       # Entwicklung noch folgende Zeile einfügen:
       # use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
    
     } # WriteError
     
  3. Wie trenne ich die Verbindung ordnungsgemäß?
    $dbh->disconnect();
  4. Wie führe ich ein INSERT-Statement aus?

    Beim Ausführen eines SQL-Insert-Statements gibt es folgende Probleme:

    1. SQL-Sonderzeichen müssen escaped werden.
    2. Ein Wert für eine Spalte darf nicht für die Datenbankspalte zu lang sein.
    3. Eventuelle Fehlermeldungen müssen abgefragt/ausgewertet werden.

      Als Beispieltabelle nehme ich folgende Tabelle für ein Mini-Gästebuch:
      # Datenbanktabelle: guestbook (id, date, name,  nachricht)
      # id: INTEGER UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY  KEY
      # date: TIMESTAMP
      # name: VARCHAR(32)
      # nachricht: TINYTEXT 
      # id ist der Primärschlüssel der Datenbank; er kann die Werte eines
      # vorzeichenlosen Integerwertes annehmen, also Zahlen von 0-65535. Durch
      # AUTO_INCREMENT ist id ein Zähler, der sich automatisch bei jedem INSERT
      # um 1 erhöht.
      # date:  ist  ein  Datum der Form: yyyymmddhhmmss. Dieses Feld hat bei MySql 
      # einen Standardwert. Wenn also kein Wert (oder NULL) in diese Spalte eingefügt
      # wird, dann wird das aktuelle Systemdatum verwendet. Dies hat den Vorteil, daß
      # man das Systemdatum nicht in Perl ermitteln muß.
      # name: dieses Feld kann beliebige ASCII-Zeichen aufnehmen, und zwar maximal 32.
      # nachricht: dieses Feld kann beliebige ASCII-Zeichen aufnehmen, und zwar maximal 255 .Stimmt das?
      	
      my $table = "guestbook";
      my $name = "Strat";
      my $message = "Hallo Strat, jetzt schreibe ich auch mal 'ne Nachricht.\nGruss Martin\n";
      
      # Verbindung zur Datenbank erstellen wie in Punkt 2 angegeben.
      
      $name = $dbh->quote($name); # 4.1.
      $message = $dbh->quote($message); # 4.1.
      
      if (length($name) > 31) { # 4.2.
        # Fehler oder Abschneiden
      }
      if (length($message) > 255) { # 4.2.
        # Fehler oder Abschneiden
      }
      
      # SQL-Statement erzeugen. Durch das $dbh->quote sind schon um $name und $message
      # einfache Hochkommatas herum, sodaß wir sie hier nicht mehr angeben brauchen.
      my $statement = "INSERT INTO $table (name, message) VALUES ($name, $message);
      
      # SQL-Statement ausführen:
      unless ($dbh->do($statement)) {
        &WriteError($dbh, "Error in executing Sql-Statement:\n\t$statement");
      }
      else {
        # Daten wurden erfolgreich eingefügt.
      }
      # Verbindung trennen, wie in Punkt 3. angegeben.
      

  5. Wie führe ich ein SELECT aus?

    # Verbindung zur Datenbank erstellen wie in Punkt 2 angegeben
    my $statement = "SELECT * FROM guestbook WHERE name = 'Strat' ";
    my $sth = $dbh->prepare($statement);
    unless ($sth) { # Fehlerabfrage
      &WriteError($dbh, "Error in preparing SQL:\n\t$statement");
    }
    
    $sth->execute() or &WriteError($dbh, "Error in executing SQL:\n\t$statement");
    
    while ( my $result = $sth->fetchrow_hashref() ) {
      foreach my $name (sort keys %$result) {
        print "$name => $result->{$name}\t";
      } # foreach
      print "\n";
    } # while
    
    $sth->finish(); # statement handle wieder freigeben
    
    

    Oft wird in Beispielen anstelle von fetchrow_hashref() oder fetchrow_arrayref() nur fetchrow() verwendet, z.B.

    while (my ($value1, $value2) = $sth->fetchrow() ) {

    was eine große Schwäche hat. Was passiert nämlich, wenn sowohl $value1 als auch $value2 in der Datenbank NULL sind? Dann werden sie in Perl zu undef, und die while-Schleife bricht ab, obwohl vielleicht noch nicht alle Daten ausgelesen worden sind.


  6. Wird fortgesetzt...

Letztes Update dieser Seite: Tuesday, 27-Jun-2006 20:37:01 CEST