10. Datenbanken und DBI Ties BerkeleyDB Datenbanken und DBI Oracle, Mysql und Proxy Server 10-1 Ties tie bildet komplexe Operationen auf Daten ab auf Manipulation einfacher Perlvariablen (Skalare, Arrays, Hashes, Filehandles) Manipulation der Variablen löst entsprechende Aktionen aus realisiert durch Subroutinen zum Lesen, Schreiben, Einfügen und Löschen von Daten Standardverhalten der Variables ist verändert Ties binden Methoden aus Packages an Variablen 10-2 Ties und Objekte Gebundene (tied) Variablen arbeiten wie Objekte das Interface ist definiert Methoden eines Packages werden gerufen Unterschied: festgelegte Namen von Methoden Ties suchen nach den gleichen Prinzipien wie bei Objekten die Methoden versteckter Polymorphismus 10-3 Realisierung von Ties ein Tie ist an eine Klasse gebunden (Package) Methoden mit festen Namen sind bereitzustellen für Skalar: TIESCALAR, FETCH, STORE, DESTROY für Hash: 9 Methoden, u.a. FIRSTKEY, NEXTKEY... Methoden werden an Variable gebunden: tie $var, $class, @args; ruft den Konstruktor $class->TIESCALAR @args; # constructor Aufruf weiterer Methoden bei Benutzung von $var Verbindung zu Methoden lösen: untie $var; 10-4 Tie Anwendungen Viele Module benutzen Tie Mechanismus derzeit über 200 Module auf CPAN, die Tie nutzen oder bei der Erstellung von Ties helfen (Tie::Scalar, Tie::Hash, ...) (im core perl) Abbildung auf Hashes am weitesten verbreitet Aber auch Bindung an Filehandles möglich Viele Module stellen Datenbankinterface bereit zu SQL Datenbanken (Tie::DBI) zu Berkeley DB (DB_File, BerkeleyDB) siehe auch perldoc perltie 10-5 Pflege von Datenbanken mit tie In UNIX gibt es viele Varianten von DBM Berkeley DB ist erste Wahl (simultane Updates, Transaktionen) diese DB's implementieren Disk basierten Hash alle mit mehr oder weniger Nachteilen (siehe perldoc AnyDBM) Modul BerkeleyDB besser als DB_File (für DB 1.x) SDBM_File (simple Database) im perl Core, auch auf Windows 10-6 tie und untie für Datenbanken Verbinden mit der Datenbank ist Aufruf von tie use Fcntl; #Constants O_RDWR and O_CREAT use DB_File; #Berkeley DB tie %h,’DB_File’,$file,O_RDWR|O_CREAT,0666,$DB_BTREE; Lesen/Schreiben/Ändern durch Benutzen von %h $val=$h{key1}; $h{key2}=’new text’; Löschen von Einträgen ist Löschen von key/value delete $h{key2}; Rückspeichern in Datenbank auf Disk durch untie untie %h; 10-7 tie Demo ### Bitte spielen Sie dieses Beispiel durch ### use Fcntl; # for the constants O_RDWR and O_CREAT use SDBM_File; # Simple DB, in Perl always available tie %hash,'SDBM_File','C:\Temp\mydb',O_RDWR|O_CREAT,0666; $hash{key1} = 11.2; $hash{key2} = 'text'; $date = localtime(time); #use the date stamp as key $hash{$date} = ''; print "In memory: ", join ("\n\t", keys %hash), "\n"; untie %hash; print "After untie:", keys %hash, "\n"; tie %hash,'SDBM_File','C:\Temp\mydb',O_RDWR|O_CREAT,0666; print "Read from file: ", join ("\n\t", keys %hash), "\n"; untie %hash; 10-8 DBM Anwendungen NIS (Yellow Pages) Maps sind DBM Files Konversionen zwischen DBM Formaten durch zwei tie Aufrufe, danach einfach %new=%old Bearbeitung von Textfiles als BerkeleyDB(RECNO) einfacher Zugriff über Perl's tie Mechanismus damit einfacher Zugriff per Zeilennummer möglich Mehrere Anwendungen nutzen BerkeleyDB spamassassin, gridengine, sendmail, firefox, ... 10-9 Editieren von Text mit DB_File use DB_File; tie @lines, 'DB_File', 'textfile', O_RDWR| O_CREAT, 0666, $DB_RECNO; $lines[0] = 'New first line'; push @lines, 'yet another new line'; $lines[5] = 'replacement for line 6'; $lines[8] = 'last line'; $lines[-1] = 'remove this line later'; $last = pop @lines; #last line gets removed untie @lines; 10-10 Relationale Datenbanken DBI (Data Base Interface) ist Schnittstelle zwischen perl und relationalen SQL Datenbanken Standardisiertes API für viele RDBMS besteht aus Modul DBI (generisch für alle DB's) und spezifischen Modulen (DBD, Datenbanktreiber) Code damit weitgehend unabhängig von RDBMS Ähnliches Konzept für Windows (ODBC) Zugriff auf DB's, die ODBC Interface haben mit DBI+DBD::ODBC (es gibt auch Win32::ODBC) 10-11 Weiterführende Literatur perldoc DBI; perldoc DBD::Oracle ... Programming the Perl DBI, Alligator Descartes & Tim Bunce, O'Reilly (2000) DBI Homepage: http://dbi.perl.org Vorträge von Tim Bunce auf: http://backpan.cpan.org/authors/id/T/TI/TIMB/ DBI_AdvancedTalk_200708.pdf DBI_WhatsNewTalk_200607.pdf OraclePerlTalk_200201.ppt 10-12 SQL (Structured Query Language) wird zur Arbeit mit RDBMS benötigt Perl reicht SQL an RDBMS ohne Prüfung durch Einfache SQL Statements INSERT INTO table (colx, coly, ...) VALUES (val1, val2, ...) UPDATE table SET colx = val1 WHERE coly LIKE val2 DELETE FROM table WHERE colz=num1 SELECT colx, coly, ... FROM table WHERE ... ORDER BY colz, ... schon bei WHERE Unterschiede zwischen DB's z.B. bei Stringvergleich: UPPER(val) LIKE .. (Oracle) val CLIKE .. (mysql) 10-13 Unterstützte RDBMS Viele RDBMS unterstützt (CPAN), bei DESY u.a.: DBD::Oracle, DBD::mysql DBD::ODBC und ADO Datenbanken (Windows) DBD::CSV Text files (Comma Separated Values) alle obige RDBMS auf allen Systemen bei Nutzung des DBD::Proxy Treibers (kommt mit DBI Modul) Nutzung der DBI Schnittstelle einfach mit use DBI; #use DBD::xxx usually not required Einige RDBMS brauchen Zusatzinformationen (s.u.) 10-14 Das DBI/DBD Interface DBI definiert einheitliche Methoden, die großteils in den DBD Treibern realisiert sind DBD Module können zusätzliche Methoden definieren, die nur für konkretes RDBMS gelten Methoden auf Datenbank- bzw. Tabellenebene brauchen database handle, erhält man mit connect Operationen innerhalb einer Tabelle brauchen ein statement handle, erhält man z.B. mit prepare 10-15 Prinzipskizze DBI/DBD (aus Talk T. Bunce) Perl Application DBI Module DBD::Oracle Oracle Server DBD::Informix Informix Server DBD::Other Other Server 10-16 Oracle mit DBI Windows: SQLPlus installieren (Netinstall) UNIX: ORACLE_HOME muss gesetzt werden: $ENV{ORACLE_HOME}='/opt/products/oracle-client/10.2g' gilt nur ab SL3 und neuer und /opt/products/perl/5.8.8/bin/perl für ältere Versionen 5.8.8 -> 5.8.2, 10.2g -> 9.2.0 Windows User dürfen diese Variable nicht setzen als DB Name 'dbi:Oracle:desy_db' verwenden! 10-17 Datenbankabfrage (Oracle) use DBI; replace for other RDBMS, DB, table $dbname = 'dbi:Oracle:desy_db'; $ENV{ORACLE_HOME}='/opt/products/oracle-client/10.2g' if $dbname =~ /dbi:Oracle:/i and $^O ne 'MSWin32'; $dbuser = $ENV{ORACLE_USERID} || 'read/read'; $dbh = DBI->connect($dbname, $dbuser, ''); $sth = $dbh->prepare(qq{select * from bolewski.teilnehmer where NAME like ?}); $sth->execute('Fri%'); # insert parameters for ? $fieldnames = $sth->{'NAME'}; # field names while ($row = $sth->fetchrow_arrayref) { print "$row->[1]: $fieldnames->[2]=$row->[2]\n"; } $sth->finish; $dbh->disconnect; 10-18 Optimierungen Benutzen von connect_cached statt connect neue Verbindungen zu DB öffnen dauert lange Verwenden von prepare und execute statt do ein prepare call für viele execute calls nutzbar Verwenden von Platzhaltern ? in prepare und Ersetzung durch aktuelle Argumente in execute Nutzung von fetchrow_arrayref statt fetchrow_array weniger Datenbewegungen, da Pointer verwendet Bei großen Projekten kann Ima::DBI hilfreich sein 10-19 Fehlerbehandlung Die meisten DBI Methoden liefern undef bei Fehler Dann steht in $DBI::errstr die Fehlermeldung Einschalten automatischer Fehlerprüfungen: $handle->{RaiseError}=1; #die on error $handle->{PrintError}=1; #warn on error $DBI::errstr wird in beiden Fällen ausgegeben Programmabbruch kann vermieden werden: $handle->{RaiseError} = 1; eval{ ...; $handle->method; ...}; if ($@) {... better error handling ...} 10-20 Fehlersuche Tracing in DBI eingebaut (global oder per Handle) Tracing kann man einschalten Output kann in File umgeleitet werden DBI->trace($level); # global tracing $handle->trace($level); # at handle level $handle->trace($level, $file); Auch mit ENV variable DBI_TRACE steuerbar DBI_TRACE=level DBI_TRACE=file DBI_TRACE=level=file normalerweise Level 1 und 2 am sinnvollsten 10-21 Proxy Server Benutzt zur Arbeit mit RDBMS wenn Datenbank nicht netzfähig ist (z.B. Access) es keinen Treiber für benutztes System gibt Firewall Direktzugriff verhindert Zahl der Klienten mit Direktzugriff klein sein muss DBI::ProxyServer benötigt Zugriff auf DB DBD::Proxy verbindet sich zu Proxyserver per TCP Proxy package kann konfiguriert werden Datenkompression, Zugriffskontrolle, Verschlüsselung 10-22 Die Proxy Architektur Application DBD::mysql DBI DBI DBD::Proxy DBI::ProxyServer RPC::pClient RPC::pServer Client Server 10-23 Proxy Server Benutzung Proxy Server wird von Kommandozeile gestartet dbiproxy --localport portnumber (für UNIX in /opt/products/perl/5.8.8, für Win im PATH) ENV Vars auf Proxy Host setzen ! (ORACLE_HOME) Standalone Skript wird zum Proxy Client durch Ändern des DB Namens im connect Aufruf oder Setzen des DB Namens in der ENV Variable DBI_AUTOPROXY, dann keine Änderung des Skripts! Benutzen Sie die Oracle Demo per Proxy 10-24 mysql per Proxy Starten Sie einen Proxy Server auf Port 1206, dann: use DBI; $dsn = 'DBI:mysql:test_perlkurs;host=mysql.ifh.de'; # dsn has to begin with dbi:xxx: and be last part of $dbname !!! # $dbname = "DBI:Proxy:hostname=????.desy.de;port=1206;dsn=$dsn"; $ENV{DBI_AUTOPROXY} = 'hostname=????.desy.de;port=1206'; # flexible $dbh=DBI->connect($dsn, ''); # or $dbh=DBI->connect($dbname,..); $sth = $dbh->prepare("SELECT * FROM user WHERE name like ?"); $sth->execute('guest'); while (@row = $sth->fetchrow_array) { print join(", ", @row[1,2]), "\n"; } $sth->finish; $dbh->disconnect; 10-25 Persistente Objekte Objekte werden am Ende eines Programms zerstört Lösung: Dauerhafte Speicherung in Datenbank durch Abbildung von Objekten auf Datenbank durch Konvertierung von Objekten in Strings Data::Dumper, Dumpvalue durch Konvertierung in binäre Daten Class::DBI, Tangram, ... Storable, FreezeThaw und anschließende Speicherung in File oder DB Komplettlösung mit Pixie 10-26 DBI Code Portabilität DBI Code weitgehend portabel, da DBI auf vielen Systemen lauffähig (Linux, Windows, Mac, ...) ProxyServer erhöht Flexibilität DBI Code reflektiert SQL Implementation der RDBMS z.B. Zugriff auf Access DB von UNIX aus! SQL Dialekte und SQL Erweiterungen DBD Treiber Einschränkungen beachten RDBMS Abhängigkeit eliminieren: einfache SQL Statements benutzen den Rest in perl kodieren, DBI hat RDBMS Infos 10-27 Weitere Themen Multithreading für DBI DBD::Multiplex Treiber Tie::DBI um SQL Syntax zu vermeiden: um mehrere DB's synchron zu halten Lastverteilung für Queries Erhöhung der Ausfallsicherheit Konsistenzprüfung mehrerer DB's $hash{table}->{field} = 42;#is SQL UPDATE DBD::Gofer als Ersatz für DBD::Proxy 10-28