Perl-Programmierung: DBI


Einleitung

Bearbeiten

Perl besitzt dank des DBI-Moduls[1] und diversen Datenbanktreibern (engl. database drivers, DBD) eine Schnittstelle, um mit verschiedenen Datenbanksystemen arbeiten zu können. Darunter fallen populäre Open-Source-Produkte wie MySQL und PostgreSQL sowie kommerzielle Riesen wie Oracle. Derzeit umfasst dieser Abschnitt die Möglichkeiten der Anbindung an MySQL, PostgreSQL und CSV-Dateien.

Zugriff auf MySQL mit DBI

Bearbeiten

Mit Perl und dem DBI-Modul ist es leicht, sich mit einer MySQL-Datenbank zu verbinden und Abfragen abzusetzen. Wenn das geeignete Perl-Modul für die Verbindung zu MySQL installiert ist ( DBD::mysql[2] ) und eine MySQL-Datenbank erreichbar ist, kann es auch schon losgehen. Elementare SQL-Kenntnisse sind dabei natürlich hilfreich. Weiterführende Erklärungen liefert die Dokumentation des Modules DBI.

Einfaches Beispiel

Bearbeiten
#!/usr/bin/perl
use strict;
use warnings;
use DBI;

# Deklaration der noetigen Variablen fuer die Verbindung
# Falls die Datenbank nicht lokal liegt, muss man zusaetzlich
# die Variablen $db_host und/oder $db_port angeben
# my $db_host = '127.0.0.1';
# my $db_port = 3306;

my ($db_user, $db_name, $db_pass) = ('deinuser', 'deineDB', 'deinpass');

# Verbindung zur DB herstellen
# alternativ ( wenn DB nicht lokal ):
# my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=$db_host;port=$db_port", 
#                         "$db_user", "$db_pass");
# Man kann auch noch Fein-Tuning betreiben, z.B. mit dem RaiseError- oder dem AutoCommit-Switch.
# Naeheres dazu steht in der Dokumentation des Modules DBI.
my $dbh = DBI->connect("DBI:mysql:database=$db_name", $db_user, $db_pass);

# Vorbereiten der SQL-Anweisung

my $query_test = $dbh->prepare('SELECT * FROM deinetabelle');

# Ausfuehren der Anweisung

$query_test->execute() or die $query_test->err_str;

# Hier koennte weitergehende Verarbeitung erfolgen, beispielsweise eine Auflistung aller Eintraege:

while (my ($col_1, $col_2, $col_3) = $query_test->fetchrow_array() ) {
    print "Spalte 1: $col_1 \n";
    print "Spalte 2: $col_2 \n";
    print "Spalte 3: $col_3 \n";
}

# Nun erstellen wir doch noch gleich eine neue Tabelle
# Statt der Möglichkeit mittels vorherigem prepare() und execute(),
# benutzen wir hier die einfache Methode do()

my $create_query = 'CREATE TABLE test_table';

$dbh->do($create_query);

# Nachdem alles erledigt ist, schließen wir die Datenbankverbindung

$dbh->disconnect();

Die eigentliche Arbeit in diesem Script steckt in Zeile 31. Hier wird mittels der Funktion fetchrow_array jeweils eine Zeile aus der Datenbank gelesen und zurückgeliefert. Die ersten 3 Werte dieser Liste werden danach den Werten $col_1 bis $col_3 zugewiesen. Sobald fetchrow_array keine Zeile mehr zurückliefert, beendet sich die while-Schleife.

Erweitertes Beispiel mit Zugangsdaten in einem Modul

Bearbeiten

Im Sinne der Sicherheit, Portabilität und Faulheit ist es von Vorteil, die Zugangsdaten in einer externen Datei ( eventuell in Form eines Moduls ) zu halten und einfach in jedes Skript einzubinden. Wenn sich die Zugangsdaten ändern, bleibt damit der Verwaltungsaufwand gering. Ansonsten müssten die Zugangsdaten in jedem Script händisch angepasst werden. Außerdem ist in diesem Fall auch die Weitergabe des Quelltextes eher unbedenklich, da die brisante Information in einer separaten Datei steckt. Die Datei mit den Zugangsdaten sollte dann verständlicherweise nicht für jedermann lesbar sein.

Im folgenden Beispiel werden die Zugangsdaten im Modul ZugangsDaten gehalten.

Die Datei mit den Zugangsdaten ( ZugangsDaten.pm ):

#!/usr/bin/perl
use strict;
use warnings;
use base 'Exporter';

our @EXPORT_OK = qw($DB_USER $DB_PASSWD $DATABASE);

package ZugangsDaten;

our $DB_USER   = 'youruser';
our $DB_PASSWD = 'yourpasswd';
our $DATABASE  = 'yourDB';

1;

Die Datei ZugangsDaten.pm sollte nun mit sicheren Zugriffsrechten versehen werden. Nachdem das erledigt ist, kann man das erste Beispiel auch wie folgt formulieren:

#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use lib '.';
use ZugangsDaten qw($DB_USER $DB_PASSWD $DATABASE);

# Verbindung zur DB herstellen

my $dbh = DBI->connect("DBI:mysql:database=$DATABASE", $DB_USER, $DB_PASSWD);

# Vorbereiten des SQL-Statements

my $query_test = $dbh->prepare('SELECT * FROM deinetabelle');

# ...
# ... alles andere bleibt gleich
# ...


Erklärung

In Zeile 5 wird Perl angewiesen das aktuelle Verzeichnis in den Suchpfad @INC aufzunehmen. Dies ist notwendig, damit die Datei ZugangsDaten.pm, wie in Zeile 6 gefordert, gefunden wird. Durch die package-Anweisung im Modul befinden sich die Variablen im Namensraum ZugangsDaten. Zur Vereinfachung exportiert das Modul Exporter die relevanten Variablen in den aktuellen Namensraum. Alternativ könnten die Variablen auch mit ihren qualifizieren Name, wie z.B $ZugangsDaten::DB_USER, angesprochen werden.

DBI-Zugriff auf andere Datenbanksysteme

Bearbeiten

Im wesentlichen können hier die Erkenntnisse des letzten Kapitels übernommen werden. Den größten Unterschied stellt lediglich die connect-Anweisung dar, die für jedes DBMS etwas anders ausschaut. Des weiteren sollten, um die folgenden Beispiele ausführen zu können, die Module DBD::Pg[3] für PostgreSQL sowie DBD::CSV[4] für CSV installiert sein. Beide Module sind im CPAN zu finden.

PostgreSQL

Bearbeiten
my $dbh = DBI->connect("DBI:Pg:dbname=$db_name", $db_user, $db_pass);

Ein CSV-Verzeichnis

Bearbeiten

CSV steht für "Comma-separated Values", und bezeichnet keine Datenbank im eigentlichen Sinne, sondern einen Dateityp, eigentlich reine Textdateien im ASCII-Format, die von jedem Texteditor gelesen und bearbeitet werden können. Damit hat der Programmierer die Möglichkeit, SQL zu nutzen, ohne ein DBMS installieren zu müssen. Vorteilhaft, wenn man sparsam mit den Ressourcen umgehen muß.

Als Datenbank verwendet man ein Verzeichnis, und jede CSV-Datei steht für eine Tabelle. Benutzername und Passwort entfallen.

my $dbh = DBI->connect('DBI:CSV:f_dir=/pfad/zu/deinem/csvverzeichnis');

#Oder bei Windows
my $dbh = DBI->connect('DBI:CSV:f_dir=c:\pfad\zu\deinem\csvverzeichnis');

SDBM (Standard-Perl-Quelldistribution) ist eine sehr einfache Datenbank, die häufig bei einer gewöhnlichen Linux-Distribution standardmäßig installiert wird. Es werden zwei Dateien erzeugt. Eine mit der Endung .dir und eine .pag, wobei letztere die Daten beinhaltet. Für SDBM-Datenbanken gibt es den DBI-Treiber DDBD::DBM[5]. Man kann aber auch das Modul SDBM_File verwenden.

Hier ein erklärendes Beispiel eingebettet in eine Klasse:

package TemperaturDB;
    
use Fcntl;                                    # O_RDWR, O_CREAT, etc.
use SDBM_File;
    
sub new                                       # Konstruktor
{
    my $this  = shift;
    my $class = ref($this) || $this;
    
    my $self  = {
        temperatur => {},                     # Temperaturwerte
    };
    
    bless $self, $class;                      # Objekt erzeugen
   
    tie(%{$self->{temperatur}}, 'SDBM_File','temperatur.db', O_RDWR|O_CREAT, 0666);
    
    return $self;
}

Der Konstruktor verbindet das Hash %{$self->{temperatur}} mit der Datenbank (temperatur.db). Im aktuellen Verzeichnis werden die Dateien temperatur.db.dir und temperatur.dp.pag angelegt bzw. benutzt.

sub write_db
{
    my $self  = shift;
    my $key   = shift;                         # Datenschluessel
    my $value = shift;                         # Datenwert

    $self->{temperatur}->{$key} = $value;

    return 1;
}

Die Funktion write_db schreibt Daten in die Datenbank.

sub read_db
{
    my $self = shift;
    my $key  = shift;                         # Datenschluessel

    return $self->{temperatur}->{$key};
}

Die Funktion read_db liest bestimmte Daten der Datenbank aus.

sub DESTROY
{
    my $self = shift;

    untie %{$self->{temperatur}};
}
1;                                            # Returnwert für Package

Der Destruktor löst die Verbindung wieder auf und schließt somit die Datenbank wieder.


Das folgende Beispiel zeigt, wie diese Klasse benutzt werden kann:

#!/usr/bin/perl
use strict;
use warnings;

use TemperaturDB;
  
my $db = TemperaturDB->new();                      # Konstruktor wird aufgerufen
$db->write_db( 'InnenTemperatur' =>  21.0);        # Daten schreiben
print 'Innentemperatur: ', $db->read_db('InnenTemperatur'), "\n"; # Daten lesen
  1. CPAN: DBI
  2. CPAN: DBD::mysql
  3. CPAN: DBD::Pg
  4. CPAN: DBD::CSV
  5. CPAN: DBD::DBM