Was sind eigentlich datenbankgestützte Websites? Welche Vorteile bieten sie gegenüber »normalen« Websites? Welche Kenntnisse braucht man, um sie zu erstellen? Das sind die Fragen, auf die wir in der heutigen Lektion eine Antwort finden wollen. Heute können wir uns einmal zurücklehnen und den Computer ausgeschaltet lassen. Sie werden lernen, was dynamische Websites sind und welche Konzepte dahinter stehen. Leider geht das nicht ohne etwas Theorie. Die heutigen Themen im Überblick:
An den vorausgegangenen Tagen haben wir uns mit der Erzeugung von statischen Websites befasst und haben gerade einmal das erste Viertel des Buches hinter uns gebracht. Zu was in aller Welt muss man nun noch so viel Papier und Druckerschwärze verbrauchen? Nun, für die Erklärung, wie man dynamische Websites erstellt. Aber was versteht man eigentlich darunter?
Wenn eine Website dynamisch ist, so heißt das, dass Inhalte eines HTML-Dokuments nicht - wie wir das bisher von HTML-Dateien kennen - statisch, also unveränderlich, sind, sondern ausgetauscht werden können. Diese neuen Inhalte werden dynamisch in Abhängigkeit von den Eingaben des Anwenders erzeugt. Nun haben wir ja schon Seiten erstellt, bei denen sich Objekte verändert oder bewegt haben, wenn der Anwender z.B. den Mauszeiger darauf gesetzt hat. Sind das also auch schon dynamische Websites? Nein, eigentlich nicht. Der Code, auf dem diese Effekte basieren, ist bereits in das HTML- Dokument integriert, alle erforderlichen Rechenoperationen werden clientseitig, vom System des Anwenders, durchgeführt.
Bei echten dynamischen Sites wird ein HTML-Dokument aus Programmcode generiert,
der vom Server abgearbeitet wird. Rufen zwei Besucher einer Site dasselbe Dokument ab,
kann sich der HTML-Code dieser Dateien durchaus unterscheiden. Zur Erstellung einer
individualisierten HTML-Seite wird also auf die Rechenleistung des Servers zugegriffen,
der das Dokument auf der Grundlage der Anwendereingaben erzeugt. Diese Seite kann
nun die Art von dynamischen Elementen enthalten, die wir in den vorhergehenden
Lektionen kennen gelernt haben, oder ein gewöhnliches statisches HTML-Dokument
sein. Der entscheidende Punkt ist, dass die Seite während der Laufzeit vom Server erzeugt
und dann an den Client übertragen wurde. Hinter dynamischen Websites steht
gewöhnlich ein Datenbanksystem, um die Datenbestände möglichst effektiv zu speichern
und zu verwalten. Dynamisch erzeugte Dokumente lassen sich manchmal an der
Extension der angeforderten Datei wie .cgi, .php
oder .jsp
- kurz allem, was von .htm
oder .html
abweicht - erkennen.
Die Extension einer Datei ist zwar noch keine hundertprozentige Garantie, dass hinter der Website eine Datenbank steht, aber doch ein ziemlich verlässlicher Hinweis. Sie ist auch ein Hinweis darauf, welche Technologie verwendet wird, um die Site dynamisch zu machen. Es gibt zwei verbreitete Ansätze, um dynamische Websites zu erzeugen: den Einsatz von CGI-Scripts und die Verwendung eingebetteter Skriptsprachen.
Traditionell konzentrierte man sich bei der Programmierung von Web-Applikationen darauf, spezialisierte Anwendungen zu schreiben, die genau definierte Aufgaben erledigen, die so genannten CGI-Scripts (CGI: Common Gateway Interface). CGI-Scripts sind Anwendungen, die sich im Prinzip nicht von den Programmen unterscheiden, die Sie lokal auf Ihrem Rechner einsetzen, nur dass sie auf einem Server installiert sind. Es sind Programme wie andere auch, nur verwenden sie ein HTML-Interface.
Das Hauptproblem von CGI-Scripts ist, dass sie eine Menge Speicherplatz auf dem Server beanspruchen. Eine typische Perl-Anwendung (Perl ist die am weitesten verbreitete Programmiersprache für CGI-Scripts) belegt ungefähr 5 MB RAM. Für einen modernen UNIX- oder NT-Server ist das noch kein Problem, wohl aber das ständige Laden des Programms in den Arbeitsspeicher und das anschließende Löschen. Diese ständigen Lade- und Löschvorgänge machen CGI-Applikationen weit ressourcenhungriger als eingebettete Scriptsprachen, auf die wir im Anschluss eingehen.
Bevor sich jetzt allgemein Unmut breit macht, möchte ich darauf hinweisen, dass man das Perl-Problem elegant umgehen kann. Mit der mod_perl-Library für den Apache-Webserver bzw. dem Perl-Add-on von ActiveState für den IIS kann man einen Perlinterpreter in den Webserver integrieren. So muss nicht jedes Mal ein eigener Perl-Prozess gestartet werden, wenn ein CGI-Script aufgerufen wird.
CGI-Scripts werden normalerweise programmiert, um eine genau definierte Aufgabe auszuführen. Auf meiner Website unter http://jray.ag.ohio-state.edu/ finden Sie verschiedene solcher CGI-Scripts. Es handelt sich nicht um die üblichen seitenlangen Webapplikationen, sondern sie sind für einen speziellen Einsatzzweck geschrieben (Besucherstatistiken, grafische Netzwerkanalyse usw.).
Der »Pferdefuß« an den herkömmlichen CGI-Programmiersprachen ist, dass sie nicht für die Programmierung von Webapplikationen konzipiert wurden. Wofür Sie bei einer herkömmlichen CGI-Applikation mehrere Dutzend Zeilen Code brauchen, lässt sich mit eingebetteten Scriptsprachen vielleicht mit einer einzigen Zeile erledigen. Wenn Sie Erfahrung mit CGI-Scripts haben, werden Sie feststellen, dass der Einsatz von eingebetteten Sprachen den Sourcecode drastisch verkürzen kann.
Eingebettete Scriptsprachen sind die Nachfolger der CGI-Sprachen. In puncto Benutzerfreundlichkeit und Leistungsumfang übertreffen sie herkömmliche CGI-Scripts bei weitem. Der Hauptunterschied zwischen CGI-Scripts und eingebetteten Scriptsprachen lässt sich am besten an der Frage festmachen, wer sozusagen die »Oberhoheit« über den Code hat. Bei CGI-Scripts steht der Code unter der Regie der Programmiersprache, die das HTML-Dokument erzeugt. Bei eingebetteten Sprachen steuert das HTML-Dokument den Code. Statt also erst ein Programm zu schreiben, das dann anschließend eine HTML-Datei ausgibt, schreiben Sie gleich den erforderlichen HTML-Code und setzen dort, wo Elemente dynamisch verändert werden sollen, den entsprechenden Anwendungscode ein.
Auch hinsichtlich der Abarbeitung unterscheiden sich die Programmiersprachen. Eingebettete Sprachen werden vom Server abgearbeitet, wenn er die Seite an den Client schickt. Hierzu muss kein externes Programm aufgerufen werden. Der Interpreter für die Sprache ist in den Server selbst eingebunden. Das macht eingebettete Sprachen höchst effektiv, was Geschwindigkeit und Ressourcenbedarf angeht.
Ein anderer fantastischer Vorteil von eingebetteten Sprachen ist, dass man mit ihnen direkt auf Datenbanken zugreifen kann. Datenbankunterstützung wurden bei den meisten Programmiersprachen erst nachträglich integriert. Die Entwickler eingebetteter Sprachen erkannten jedoch frühzeitig das Potenzial, das im direkten Zugriff auf Datenbanken aus dem HTML-Code heraus liegt und integrierten dieses Feature von vorneherein in diese Sprachen. Geschwindigkeit und leichte Anwendbarkeit sind nur zwei der Vorteile dieser optimal aufeinander abgestimmten Technologien.
Die Kombination von eingebetteten Scriptsprachen und HTML-Code bietet also große Vorteile. In den letzten zwei Jahren sind eingebettete Sprachen daher zu einem wahren Siegeszug angetreten und werden mittlerweile auf breiter Front eingesetzt. UltraDev unterstützt drei Typen eingebetteter Scriptsprachen und ist somit flexibel einsetzbar. Außerdem erlaubt das Programm als eines der ersten dieser Art eine Live-Vorschau dynamischer Websites.
Auch wenn es vielleicht den Anschein hat, dass sich die Entwicklung einer dynamischen Website bis auf den Punkt, dass sie eine HTML-Oberfläche benötigt, in nichts von der Programmierung einer anderen Anwendung unterscheidet, so ist hierbei doch eine völlig andere Vorgehensweise vonnöten. Was den Entwicklern von Web-Applikationen das Leben etwas vergällt, ist das HTTP-Protokoll. Was geschieht zum Beispiel, wenn Sie eine Anwendereingabe entgegennehmen, sie verarbeiten, eine weitere Information abfragen, sie verarbeiten und dann das Ergebnis ausgeben? Mit einer gewöhnlichen Programmiersprache ist das kein Problem. Sie strukturieren den Programmablauf genau in der Reihenfolge, wie die einzelnen Bearbeitungsschritte ausgeführt werden sollen.
Soll eine Anwendung im Web laufen, müssen Sie an die Programmierung anders herangehen. Der Grund liegt darin, dass immer nur ein Programmschritt auf einmal implementiert werden kann und dass diese Programmschritte irgendwie miteinander verknüpft werden müssen. Nun ist aber das HTTP-Protokoll ein verbindungsloses Protokoll, und zwischen Client und Server besteht zwischen dem Aufruf von zwei dynamisch erzeugten Seiten keine Verbindung. Jede einzelne Seite, die ausgegeben wird, ist - sofern sie dynamisch erzeugt wurde - das Ergebnis der individuellen Ausführung eines Programms auf dem Server.
Wenn der Anwender ein Formular abschickt, geht es an den Server, wird dort abgearbeitet und an den Anwender wird eine Ergebnisseite übermittelt. Nach der Übertragung sind die Daten auf dem Server nicht mehr existent und die Verbindung zwischen Client und Server wurde gelöscht. Also, was tun, wenn Sie diese Daten eigentlich für weitere Operationen benötigen?
Um eine konstante Verbindung zwischen Client und Server über mehrere Anwenderzugriffe hinweg aufrecht zu erhalten, müssen Sie die Eigenheiten des HTTP- Protokolls überlisten und mit einem so genannten Session-Management arbeiten. Einfach ausgedrückt ist das Session-Management ein Trick, um zwischen dem Anwender und dem Webserver eine permanente virtuelle Verbindung einzurichten, während in Wirklichkeit keine dauerhafte Verbindung besteht. Für die Realisierung eines Session-Managements können Sie zwischen zwei Möglichkeiten wählen - dem Einsatz von Cookies und der Übergabe von Variablen.
Variablenübergabe ist eine Möglichkeit, die Werte von verschiedenen Variablen von einem HTML-Dokument an das nächste weiterzugeben. Sie kennen sicher URLs wie die folgende, die sich nicht auf eine bestimmte statische HTML-Seite beziehen:
http://www.someplaceurl.com/test.jsp?firstname=John&lastname=Ray
In diesem Beispiel werden die Variablen firstname
und lastname
an das Programm
test.jsp
auf dem Server mit den Werten John
bzw. Ray
übertragen. Sollen bei einer
Anwendung Daten zwischen Seiten übergeben werden, kann man diese Werte in
Variablen ablegen und an den Link anhängen, der diese Seite aufruft. Wird der Link
aktiviert, werden die Daten »weitergereicht«. Man bezeichnet diese Art der
Variablenübergabe als GET-Methode. Sie wird häufig verwendet, doch erzeugt sie
hässliche Monster-URLs, die zudem manchmal unerwünschte Einblicke ins Innenleben
einer Website zulassen. Ein weiterer Nachteil ist, dass beim Bookmarken von Seiten, die
mit der GET-Methode erzeugt wurden, diese Variablen mit abgelegt werden. Werden
diese Seiten nun wieder aufgerufen, werden auch die Variablen wieder mitgesendet, die
beim ersten Aufruf der Seite vom Webserver erzeugt wurden. Der Vorteil der
Variablenübergabe per GET-Methode ist, dass man die erforderlichen Links gut von Hand
erzeugen kann. Parameter aus Datenbankabfragen oder an anderer Stelle eingegebene
Benutzerdaten lassen sich so problemlos in einen Link schreiben.
Es folgt ein Codebeispiel für einen Request an den Webserver unter Verwendung der GET-Methode:
GET /thetest.jsp?firstname=John&password=notonyourlife&lastname=Ray&action=transferbankfunds HTTP/1.0
Host: poisontooth.com:
User-Agent: Johnclient.pl (Linux)
Daten lassen sich alternativ auch per POST-Methode übergeben. Sie wird gewöhnlich dann verwendet, wenn man Formulardaten an den Server übermitteln möchte, ohne dabei sämtliche Daten in die URL einbetten zu müssen. Gerade bei sehr umfangreichen Formularen ist es nicht wünschenswert, Daten per URL zu übergeben. Die POST- Methode sendet Daten als Teil der Request-Mitteilung an den Server.
POST /thetest.jsp HTTP/1.0
Host: poisontooth.com:
User-Agent: Johnclient.pl (Linux)
Content-type: application/x-www-form-urlencoded
Content-Length: 75
firstname=John&password=notonyourlife&lastname=Ray&action=transferbankfunds
Wie Sie sehen, sind die Unterschiede zwar klein, aber umso weitreichender. Abgesehen davon, dass der resultierende HTML-Code übersichtlicher ist, können auch größere Datenmengen per Formular an das Programm übergeben werden.
Mit dem POST-Befehl können Sie jedoch nur dann Daten per HTML übergeben, wenn Sie Formulare benützen. Sie können nicht selber eine URL erzeugen und damit per POST-Befehl Daten übergeben. Dadurch lässt sich die POST-Methode nur begrenzt einsetzen. Verwenden Sie jedoch eine Reihe von Formularen, die der Anwender ausfüllen soll, ist die POST-Methode sehr nützlich.
Egal für welche Art der Variblenübergabe Sie sich letztlich entscheiden, das Problem, wie Sie Ihre Daten verwalten, ist damit noch nicht gelöst. Wenn Sie z.B. eine Warenkorb- Funktion programmieren wollen, die alle gekauften Waren in einer Einkaufsliste speichert, wäre es nicht gerade effizient, eine Warenkorb-Variable zu definieren, an diese Variable dann alle Bestellnummern zu hängen und dann per URL an die nächste Seite zu übergeben. Zur Übergabe dieser Informationen empfiehlt sich die Verwendung von Sitzungsvariablen.
Sitzungsvariablen sind virtuelle Variablen, die für die Dauer einer Anwendungssitzung vergeben werden. In Sitzungsvariablen lassen sich beliebige Werte ablegen, die nur für die jeweilige Sitzung gültig sind. Da sich die Dauer einer Anwendersitzung nicht vorhersagen lässt, werden die Variablen gelöscht, sobald der Anwender die Seite wieder verlässt. Manchmal werden Sitzungsvariablen auch zeitabhängig gelöscht. Der Anwender wird dann automatisch vom System ausgeloggt, und die gespeicherten Informationen werden gelöscht. Haben Sie nicht auch schon mal einen Webshop besucht und ein paar Dinge in Ihren Einkaufskorb gelegt, um sie dann schließlich doch nicht zu kaufen? Wahrscheinlich haben Sie dann Ihren Einkaufswagen nicht geleert, sondern einfach das Browserfenster geschlossen. Falls Sie dann am nächsten Tag nochmal auf die Site gegangen sind, war Ihr Einkaufskorb wahrscheinlich leer, d.h., die Sitzungsvariable wurde gelöscht.
Sitzungsvariablen können, wenn sie intelligent eingesetzt werden, sowohl dem Anwender als auch dem Programmierer das Leben leichter machen. Man kann damit sowohl komplexere als auch sicherere Anwendungen schreiben, als das unter der Verwendung der üblichen Art der Variablenübergabe möglich wäre. Werden Anwendungen mit Sitzungsvariablen aber nicht sauber programmiert, kann sich der Effekt ins Gegenteil verkehren. Bei den meisten Programmiersprachen, die die Definition von Sitzungsvariablen gestatten, können Sie die vollständige Warenkorbstruktur in einer einzigen Variablen abbilden. Das ist zwar möglich, kann aber den Server schon mal in die Knie zwingen. Komplexe Strukturen, die in einer einzigen Variablen abgelegt werden, müssen zuerst serialisiert, d.h. in eine Datenfolge umgewandelt werden, die auf dem Server gespeichert werden kann. Wird die Information nun aus irgendeinem Grund noch einmal abgerufen, muss sie wieder zurückkonvertiert werden. Laufen mehrere solcher Prozesse simultan ab, kann ein Server in puncto Rechenzeit und Ressourcen schon mal an seine Grenzen kommen.
Es empfiehlt sich daher, Datenbanken so zu modellieren, dass sie die Struktur der Daten logisch abbilden, und für den Zugriff auf die einzelnen Datensätze jeweils eigene Sitzungsvariablen zu definieren. Der Webserver kann dann sämtliche Daten an den Datenbankserver weitergeben und wird dadurch entlastet.
Ein weiterer Variblentyp, der bei dynamischen Anwendungen zum Einsatz kommt, ist die so genannte Applikationsvariable. Dieser Typ von Variable wird für sämtliche Anwendersitzungen definiert und kann von der gesamten Webanwendung jederzeit abgerufen werden.
Ähnlich globalen Variablen gelten Applikationsvariablen als wenig sinnvolles Konzept. Zur Erstellung interner Statistiken von Webanwendungen können sie jedoch recht nützlich sein.
Über Session-IDs lassen sich Anwendersitzungen eindeutig identifizieren. Sie sind eine »Gedächtnisbrücke« für den Server, die ihm hilft, sich an bestimmte Werte wieder zu »erinnern«, die der Anwender während einer Session bereits eingegeben hat. Für den Programmierer heißt das, dass er lediglich eine ID von einer Seite zur nächsten übergeben muss, mehr nicht. Leider gibt's auch hier ein kleines Problem mit der Bookmark-Funktion des Browsers. Wird eine URL mit einer Session-ID in der URL als Lesezeichen abgespeichert, kann es - je nachdem, wie die Anwendung konfiguriert ist - zu Fehlermeldungen wie »session expired« oder nicht vorhersehbaren Fehlfunktionen kommen, wenn die Seite wieder aufgerufen wird.
Die perfekte Lösung wäre, wenn man das Session-Management so handhaben könnte, dass man Variablen ohne spezielle Programmierung weitergeben kann und die Vorgänge für Anwender und Programmierer transparent sind. Und diese Möglichkeit gibt es: Cookies.
Cookies sind eine Möglichkeit, wie eine Webanwendung auf dem Clientrechner Informationen ablegen und wieder auslesen kann. Bei vielen Anwendern läuten beim Thema Cookies allerdings die Alarmglocken. Wenn Cookies auf meinem Rechner Daten ablegen können, wer garantiert mir dann, dass sie nicht irgendwelche unerwünschten Transaktionen vornehmen und Daten auf meinem Rechner zerstören? Nun, das ist schon der schlichten Dateigröße wegen nicht möglich. Cookies können gerade mal einige Tausend Bytes haben - was kaum ausreicht, um eine größere Menge an sinnvollen Informationen zu speichern, geschweige denn ganze Programme. Zudem werden Cookies in einer eigenen Datei gespeichert. Sie können diese Datei jederzeit öffnen und ihre Inhalte überschreiben oder löschen.
Als Netscape-Anwender können Sie nach der Datei cookies.txt
suchen, verwenden Sie
den Internet Explorer, sehen Sie im Ordner Cookies im Windowsverzeichnis nach.
Nachfolgend ein Ausschnitt aus meiner eigenen Cookie-Datei:
#Netscape HTTP Cookie File
#http://www.netscape.com/newsref/std/cookie_spec.html
#This is a generated file!Do not edit.
free.aol.com FALSE /tryaolfree FALSE 993674880 user 31031923
.excite.com TRUE / FALSE 1057815167 mesp_popup y2k%fDyes
.excite.com TRUE / FALSE 1057815167 UID 9A7BF6F2Df023B94
.excite.com TRUE / FALSE 1057815167 registered no
.doubleclick.net TRUE / FALSE 1920499223 id 8bccs8ce
.deja.com TRUE / FALSE 1102550463 GTUID 04.48861.3.0.f.4363
Jede kommerzielle Website verwendet aus dem einen oder anderen Grund Cookies. Meine Cookie-Datei zählt momentan gut 400 Cookies, obwohl ich meistens technikorientierte Sites ansurfe und nichts online einkaufe.
Ein weiterer Vorbehalt gegen Cookies ist, dass man mit ihrer Hilfe das Surfverhalten von Anwendern über mehrere Websites hinweg verfolgen kann. Für manche Sites ist das zwar richtig, aber nur, weil diese Sites untereinander kooperieren. Cookies sind so konzipiert, dass die darin gespeicherte Information nur von der Site ausgelesen werden kann, die das Cookie gesetzt hat. Damit soll Datenklau seitens anderer Webanwendungen verhindert werden. Für die einzelne Site ist es jedoch sehr wohl möglich, die Aktionen des Anwenders zu rekonstruieren. Und das ist ja genau das, was wir erreichen wollen: bestimmte Vorgänge auf der Website einem einzelnen Anwender zuordnen.
Mithilfe von Cookies kann der Programmierer ohne besonderen Programmieraufwand Variablen setzen, auf die von jeder Seite der Website aus zugegriffen werden kann. Cookies werden mit einer Pfadangabe gesetzt. Seiten, die innerhalb dieses Pfades stehen, haben Zugriff auf das Cookie. Den folgenden Code schickt eine Website an den Browser mit der Anfrage, ob ein Cookie gesetzt werden darf:
Set-Cookie: SESSION=3424; path=/shopping
Sobald das Cookie gesetzt ist, wird jedes Mal, wenn der Client eine URL anfordert, die innerhalb des Verzeichnisses »Shopping« steht, an den Server folgende Mitteilung geschickt:
Cookie: SESSION=3424
Mit der Anweisung path=/
definiert die Webanwendung, wann und von welchen Seiten
aus der Client die Cookie-Information an die Webanwendung zurückschickt.
Wie sieht nun der typische Einsatz von Cookies in Webanwendungen aus? Sind sie ein »Speichermedium«, das sämtliche Informationen aufnimmt, die zwischen den einzelnen Seiten einer Webanwendung übergeben werden müssen? Das wird wohl nur in den seltensten Fällen so sein, wenn die Informationsmenge so gering ist, dass man diese Daten am besten direkt in ein Cookie schreibt. Arbeiten Webanwendungen mit Sitzungsvariablen, dienen Cookies gewöhnlich der Speicherung der vergebenen Session- IDs.
Eine Frage wird zwangsläufig immer wieder gestellt: »Soll ich auf meiner Website mit Cookies arbeiten?« Ich persönlich halte Cookies für eine wunderbare Sache, um mit dem geringsten Programmieraufwand dem Besucher ein Höchstmaß an Anwendungsfreundlichkeit zu bieten. Wenn Sie Ihre Besucher darüber aufklären, warum und wie Sie Cookies einsetzen, dürfen Sie auch mit entsprechender Akzeptanz rechnen. Die Alternative zu Cookies wäre, mit Variablenübergabe zu arbeiten, eine in meinen Augen alles andere als verlockende Perspektive. Bei den verschiedenen Webanwendungen, die wir im Laufe dieses Buches noch gemeinsam entwickeln werden, werden wir jeweils die Techniken verwenden, die für den jeweiligen Zweck am sinnvollsten sind.
Mit UltraDev können Sie beide Varianten des Session-Managements automatisieren. Das Programm erlaubt sowohl die Verwendung von Cookies als Art globaler Variable als auch die Übergabe von Variablen an die nächste Seite per Link.
Die Entscheidung, ob und wann man eine Website um dynamische Funktionen erweitert, sollte nicht überstürzt getroffen werden. Ich habe Websites betreut, die aus den unterschiedlichsten Gründen als statische Websites konzipiert und umgesetzt wurden. Die monatliche Aktualisierung dieser Sites erfordert nun aber jedes Mal mehrere Arbeitsstunden, um alle betroffenen Seiten auf den neuesten Stand zu bringen. Je umfangreicher solche Sites mit der Zeit werden, desto aufwändiger wird es, sie zu warten, und umso größer werden die Schwierigkeiten, sie dynamisch an eine Datenbank anzubinden. Es empfiehlt sich dringend, für jede Website, die aus mehr als einem HTML- Dokument besteht, eine Sitemap anzulegen, auch wenn dies am Anfang völlig überflüssig erscheint. Eines vielleicht gar nicht so fernen Tages werden Sie ganz froh darüber sein.
Wenn abzusehen ist, dass eine Website häufig aktualisiert werden muss, ist sie ein »Bilderbuchkandidat« für eine Datenbankanbindung. Dynamische Websites entlasten den Bearbeiter von der lästigen Pflicht, jedes Mal den gesamten HTML-Code aktualisieren zu müssen, wenn sich ein Inhalt ändert. Sie müssen nur einmal eine Dateneingabemaske erstellen, mit der sich dann ebenso leicht arbeiten lässt wie mit einer gewohnten Office- Anwendung.
Auch Sites, bei denen größere Mengen an Benutzerdaten anfallen, eignen sich gut zur Dynamisierung. Erstaunlich oft werden die Ergebnisse von Anwenderbefragungen und Kundenkommentare einfach als E-Mails zusammengefasst und an den Betreiber der Site weitergeleitet. Einige Hundert CGI-Applikationen sind in der Folge damit beschäftigt, diese per Formular gewonnenen Daten in lesbaren Text umzuwandeln und dann per E-Mail an ein Wesen aus Fleisch und Blut zur endgültigen Bearbeitung weiterzuleiten. Da ist es dann interessant zu hören, dass es eigens Programme gibt, die solche per Webanwendung generierten E-Mails zur leichteren Bearbeitung auf Empfängerseite aufbereiten und in Datenbanken speichern. Wäre es da nicht viel einfacher, diese Daten nicht gleich von Anfang an in einer Datenbank zu erfassen, anstatt den Umweg über Formular zu E-Mail und von E-Mail zu Datenbank zu gehen?
Ähnlich verhielt es sich bei einigen großen kommerziellen Sites, an deren Redesign ich mitgearbeitet habe. Anfragen zu Produkten oder andere Daten, die ein Anwender in ein Formular auf der Website eingeben hatte, wurden per E-Mail an den Betreiber der Site weitergeleitet. Dort wurden die E-Mails vom Systemadministrator ausgedruckt und an die verschiedenen Kundenbetreuer zur endgültigen Bearbeitung weitergeleitet. Das ist eigentlich nicht die Art von Prozedere, an die man beim Wort E-Commerce denkt. Hier zeigte sich einmal mehr, wie schwierig es ist, bestimmte Praktiken wieder auszumerzen, wenn sie sich erst einmal eingeschliffen haben.
Und schließlich eignen sich alle Websites zur Umstellung auf Datenbanken, die große Mengen von Information hosten (und die für den Anwender gut navigierbar gemacht werden sollen). Hat der Anwender z.B. die Möglichkeit, ganze Bücher zu durchsuchen und sich die Ergebnisse strukturiert anzeigen zu lassen, so ist dies für den Nutzwert natürlich unvergleichlich höher, als nur den reinen Text zur Verfügung zu stellen oder allgemeine Informationen über das Buch. Kann der Anwender seine Suchabfragen selbst definieren, wird eine Webdatenbank zu einem fantastischen Recherchewerkzeug.
Der erste Schritt zur Umsetzung einer dynamischen Website besteht in der gründlichen Planung. Wenn Sie schon im Vorfeld die richtigen Entscheidungen treffen, kann Ihnen das später so manches graue Haar ersparen - es ist nämlich alles andere als leicht, eine bis dato statische Website datenbankgerecht aufzubereiten. Tatsächlich können Sie sich gar nichts Schlimmeres antun, als eine Website zunächst statisch anzulegen und sich dann im Nachhinein doch dafür zu entscheiden, die Site an eine Datenbank anzubinden. Je umfangreicher und vielschichtiger eine Site wird, desto stärker sind HTML-Code und Inhalt ineinander verzahnt. In solchen Fällen lässt sich der Übergang von der statischen Website zur dynamischen Webanwendung meistens nur durch völlige Neugestaltung bewältigen. Nachfolgend wird auf die einzelnen Planungsschritte eingegangen.
Erstellen Sie eine detaillierte Sitemap der Website mit allen Bereichen und einer kurzen Beschreibung der Inhalte, die unter diesen Bereichen liegen. Die Sitemap ist das A und O bei der Planung und Umsetzung einer jeden Website, und für dynamische Websites gilt das noch in weit höherem Maße. Wenn Sie sämtliche Seiten und ihre wechselseitigen Bezüge in einem klaren Struktogramm erfassen, können Sie damit auch gut die Beziehungen erkennen, die zwischen den Daten dieser Seiten bestehen.
Stellen Sie fest, ob und welche Informationen in den jeweiligen Bereichen mehrfach vorhanden sind. Häufen sich solche Elemente oder sind sie sehr umfangreich, kann man sie in einer Datenbank ablegen. Bei der Identifizierung solcher Elemente sollten Sie natürlich den gesunden Menschenverstand walten lassen. Nur weil das Wörtchen »der« 19 Mal auf einer Seite vorkommt, sollten Sie es nicht bei jedem Auftreten aus der Datenbank abrufen. Adressen, Kontaktinformationen, Telefonnummern u.ä. - das sind unsere Kandidaten, die sich zur Aufnahme in die Datenbank empfehlen.
Überprüfen Sie, ob es irgendwelche Listen mit Informationen gibt, die mehr als einige wenige Einträge umfassen. Listen sind eigentlich schon eine Art Datenbank, nur sind sie nicht in elektronischer Form gespeichert. Auf jeder Website gibt es z.B. Linklisten oder Listen von Presseberichten. Diese Listen werden meistens von Mitarbeitern der Firma gepflegt und nicht von der betreuenden Internetagentur. In den Firmen, mit denen ich zu tun hatte, erledigten das die PR- bzw. die Personalabteilung, die die neuen Daten dann an die Agentur weitergaben. Je länger die Liste war, desto häufiger waren auch doppelte Einträge.
Finden Sie heraus, ob es auf den verschiedenen Seiten Elemente gibt, die häufig verändert oder aktualisiert werden müssen. Der »Lesetipp der Woche« oder ähnliche kurzfristig wechselnde Aufmacher lassen sich gut über eine Datenbank generieren. Ist die Werbeaktion abgelaufen, kann das Buch - um bei diesem Beispiel zu bleiben - in den Archivbereich der Site verschoben werden, sodass sich Interessenten auch später noch über diesen Titel informieren können.
Das Wichtigste bei der Planung datenbankgestützter Websites ist der Grundsatz der Verhältnismäßigkeit. Es gibt keine unfehlbaren Gesetze, wann und unter welchen Umständen eine Website an eine Datenbank angebunden werden sollte oder nicht. Besteht Ihre Site nur aus zwei oder drei HTML-Dokumenten, lohnt es den Aufwand nicht, einen Datenbank- bzw. Anwendungsserver aufzusetzen, um sie ins Netz zu stellen. Bei so kleinen Sites ist manuelle Datenpflege das Mittel der Wahl.
Als professioneller Webdesigner werden Sie allerdings von Kundenseite oft mit der Forderung konfrontiert, dass mit der erstellten Website kein hoher Wartungsaufwand verbunden sein soll. Selbst in diesen Zeiten des Internetbooms möchten die Leute möglichst wenig mit HTML und allem, was damit zusammenhängt, zu tun haben. Die Einrichtung eines Datenbank-Backends ist in solchen Fällen die einfachste Lösung, die Informationen auf der Site von einer Anwendung aus zu verwalten. Der Kunde kann somit seine Website stets auf dem neuesten Stand halten, ohne an irgendeinem Punkt mit dem Code in Berührung zu kommen.
Und schließlich gibt es noch die Leute, die einfach jeder Mode hinterher rennen. Und bei Websites geht der Trend augenblicklich weg von statischen und hin zu dynamischen, datenbankgestützten Anwendungen. In dieser Hinsicht habe ich durchaus schon einige unangenehme Erfahrungen gemacht. Manche Leute wollen einfach nicht einsehen, dass es Fälle gibt, in denen die damit verbundenen Nachteile in keinem Verhältnis zu den wenigen Vorteilen stehen. Statt einfach, um ein Beispiel zu nennen, ein paar Zeilen im HTML-Code anzupassen, muss man nun erst einmal die Datenbank nach dem zugehörigen Datensatz durchsuchen und ihn dann dort ändern. Datenbankgestützte Websites sind in manchen Fällen auch deshalb schwerer zu warten, weil sie, einmal abgesehen von zusätzlich erforderlichen Arbeitsschritten, auch höhere Anforderungen an das Know-how des Bearbeiters stellen. Mit einem UNIX-Zugang und einem einfachen Palm Pilot könnte ich mich auf nahezu jedem Server einloggen und Änderungen an einer Website durchführen. Liegen die Daten in einer Datenbank, dann geht das nicht mehr so leicht.
Treffen Sie diesbezügliche Entscheidungen nur nach reiflicher Überlegung. Setzen Sie nicht irgendwelche Technologien ein, nur weil Ihnen jemand weismachen will, Sie müssten das tun. Vielleicht realisieren Sie eine statische Website und stellen später fest, dass Sie besser doch eine datenbankgestützte Anwendung erstellt hätten. Doch kann es Ihnen genauso gut passieren, dass Sie eine dynamische Website erstellen, die sich als statische Website besser und einfacher hätte pflegen lassen. Die Kunst besteht darin, den später möglicherweise entstehenden Schaden möglichst gering zu halten.
Doch bevor wir überhaupt eine datenbankgestützte Website ins Netz stellen können, brauchen wir erst einmal ein Datenbank-Backend, aus dem wir unsere Daten holen können. UltraDev liefert kein solches Backend und sucht auch keines für uns aus. Bevor wir also mit UltraDev dynamische Websites entwickeln können, müssen wir auf unserem Rechner zuerst einen Datenbankserver oder zumindest eine Datenbank wie z.B. MS Access installieren. Aber keine Bange, Sie erhalten später eine schrittweise Anleitung, wie Sie eine MySQL-Datenbank einrichten. Diese Datenbank ist für UNIX-Systeme als Freeware und für Windows NT-Rechner als Shareware erhältlich. Somit kann sie auf jeder beliebigen Plattform, eingeschlossen Mac OS X, eingesetzt werden, und das in vielen Fällen unentgeltlich.
Bevor Sie eine Datenbank anlegen, sollten Sie über die Grundlagen des Datenbankenentwurfs Bescheid wissen. Leider ist es nicht damit getan, dass Sie ein paar Werte in eine Tabelle schreiben und das Ganze dann unter dem Namen Datenbank speichern. Zuerst müssen Sie sich eine Strategie überlegen, wie Sie Ihre Daten sinnvoll strukturieren, damit Sie mit der gespeicherten Information effektiv arbeiten können.
Lassen Sie uns daher anhand eines Beispiels den Aufbau einer sauberen Datenstruktur nachvollziehen.
Wenn Sie eine Datenbank anlegen, sollten Sie auch die damit verbundene Terminologie kennen. Beginnen wir mit dem Wichtigsten: Was versteht man unter Normalisierung?
Unter Normalisierung versteht man den Prozess, eine Menge von Daten so weit zu reduzieren, dass sämtliche Redundanzen, also mehrfach vorhandene identische Datensätze, ausgeschlossen sind. Hierarchische Datenbanksysteme speichern mehr Daten, als tatsächlich erforderlich sind. Durch Normalisieren wird diese monolithische Datenstruktur heruntergebrochen in mehrere kleinere, besser handhabbare »Datenpakete«. Ziel der Normalisierung ist es, Redundanzen auszuschließen und die Aktualisierung des Datenbestands zu vereinfachen.
Der Prozess der Normalisierung erfolgt in mehreren Schritten, wie wir heute noch sehen werden. Diese Schritte kann man als Etappen sehen, um die eine Datenmenge Zug um Zug der endgültigen Form zugeführt wird, die sie dann in der Datenbank haben wird.
Entitäten sind so etwas wie ein Oberbegriff, unter dem wir spezielle Daten speichern. Praktisch sind sie gleichbedeutend mit den Tabellen in einer Datenbank. Tatsächlich benennt man die Tabellen einer Datenbank nach diesen aufgestellten Entitäten.
Entitäten setzen sich aus Attributen zusammen. In gewöhnliche Datenbanksprache
übersetzt heißt das, dass Tabellen Felder enthalten. Ein Attribut ist ein Feld innerhalb
einer Entität. Sie heißen Attribute, weil sie die Entität näher beschreiben. Die Entität Auto
könnte z.B. die Attribute Jahr
oder Farbe
besitzen.
Unter Identifikationsschlüssel versteht man ein Attribut oder eine Gruppe von Attributen, über die ein bestimmter Datensatz und nur dieser Datensatz eindeutig identifiziert werden kann. Für die Definition eines Identifikationsschlüssels gelten drei feste Vorschriften:
Beziehungen sind genau das, was sich im Namen ausdrückt - die Art und Weise der Verbindung, die zwischen zwei Informationen oder Datensätzen besteht. Folgende drei Arten oder Grade der Beziehung sind zwischen Entitäten möglich:
Kurs
und Raumnummer
stehen in einer 1:n-Beziehung, denn von
einem bestimmten Raum kann es nur eine Instanz geben, aber dieser Raum kann von
mehreren Kursen benutzt werden. Die meisten Datensätze fallen unter diese Art von
Beziehung.
Nehmen wir an, Sie möchten eine Datenbank für eine Schule erstellen, die die folgenden Informationen enthält:
Der erste Gedanke wäre vielleicht, nun die Datenbank auf der Basis einer einfachen
Tabelle zu erstellen und in den Spalten Dozent
, Kurse
, Teilnehmer
und Raumnummern
die
entsprechenden Informationen einzutragen. Wenn wir das mit ein paar einfachen
Datensätzen durchspielen, sehen wir jedoch bald, wo bei diesem Datenmodell das
Problem liegt. Werfen Sie einen Blick auf Tabelle 6.1.
Wie Sie sehen, lassen sich mit dieser Tabelle die vorhandenen Daten zwar bequem
erfassen, aber die Art der Erfassung macht sie nicht besonders tauglich für praktische
Zwecke. Nehmen wir beispielsweise an, Sie möchten herausfinden, welche Kurse ein
bestimmter Teilnehmer besucht. Dazu müssten Sie alle Dozenten durchgehen und die
Spalte Teilnehmer
überprüfen. Das ist in höchstem Maße Zeit raubend und ineffektiv. Um
unser Suchverfahren optimieren zu können, müssen wir unseren Datenbestand
normalisieren. Zu diesem Zweck werden wir uns heute mit der ersten, zweiten und dritten
Normalform auseinander setzen. Es gibt zwar noch weitere Normalformen, doch die ersten
drei sind die wichtigsten. Mit jedem Schritt wird ein höherer Grad der Normalisierung
erreicht.
Um Daten in eine Normalform zu bringen, muss man sie in Entitäten zusammenfassen.
Wir beginnen mit der Entität Dozent
, unter der wir die Attribute Namen der Dozenten
,
Kurse
, Teilnehmer
, Raumnummern
ablegen. Abb. 6.1 zeigt die grafische Darstellung der
Entität Dozent
. Um unser Datenmaterial vollständig zu normalisieren, müssen wir
unserem Datenbankmodell noch weitere Entitäten hinzufügen. Am Schluss wird es nicht
mehr viel gemeinsam haben mit unserem momentanen Modell.
Abbildung 6.1: Die Basisentität Dozent
nach dem Ausgangsdatenmodell
Die erste Normalform verlangt, dass alle Entitäten eindeutig sein müssen und alle Attribute nur einfache Attributwerte aufweisen, also nicht mehrfach vorkommen dürfen. Um herauszufinden, ob sich Attribute wiederholen, überprüfen wir einfach, ob irgendwelche Attribute im Plural stehen. Und da haben wir gleich mehrfach Anlass, uns am Kopf zu kratzen:
All diese Attribute wiederholen sich und dürfen daher nicht in der Entität Dozent
enthalten sein, wenn wir unsere Daten in die erste Normalform bringen wollen. Zu diesem
Zweck müssen wir diese Attribute herunterbrechen und in ihrer eigenen Entitätentabelle
erfassen. Ferner müssen wir überprüfen, ob alle Attribute in die kleinsten sinnvollen
Entitäten aufgesplittet worden sind. So sollten Namen z.B. in Vornamen und Nachnamen
aufgeteilt werden. Abb. 6.2 zeigt unsere neue Sammlung von Entitäten, die auch gleich
um ein paar Attribute erweitert wurden.
Abbildung 6.2: Sich wiederholende Attribute erhalten ihre eigene Tabelle.
Wir haben jetzt also vier verschiedenen Tabellen: Dozent
, Kurs
, Teilnehmer
, Raum
. Und
weil's grad so schön war, habe ich die Entitäten gleich um ein paar Attribute erweitert:
Dozent - vname, nname, status, gehalt
Kurs - bezeichnung, zeit, thema, level
Teilnehmer - vname, nname, alter, level
Raum - nummer, plaetze, einrichtung
Jede Entität ist nun eindeutig und enthält keine sich wiederholenden Attribute. Die Entitäten enthalten sich aber nur selbst und haben keine Beziehung zueinander. Somit können wir aus diesem Datenmodell immer nur die Informationen beziehen, die innerhalb einer Entität abgelegt sind. Damit hat dieses Modell allerdings keinen besonderen praktischen Wert für uns. Um nun die Daten zueinander in Beziehung zu setzen, brauchen wir Identifikationsschlüssel.
Lassen Sie uns die einzelnen Entitäten der Reihe nach dahingehend untersuchen, was wir als Identifikationsschlüssel verwenden können.
Die Entität »Dozent
« muss irgendwie adressiert werden können. Der erste Gedanke wäre
vielleicht, die Namen der Dozenten als Identifikationsschlüssel zu verwenden. Aber, so
muss man sich fragen, ist dieser Wert immer eindeutig und unveränderlich? Da es sich um
Personennamen handelt, muss diese Frage mit Nein beantwortet werden. Selbst wenn
dieser Fall aller Wahrscheinlichkeit nach nie eintritt, darf die potenzielle Möglichkeit
dennoch nicht gegeben sein, damit das Datenmodell korrekt ist. Aus diesem Grund müssen
wir für die Entität Dozent
einen eindeutigen Identifikationsschlüssel einführen. Wir tun das
mit dem Attribut persNr
, also einer Personalnummer. Das kann ein beliebiger Wert sein,
solange er eindeutig ist. Die meisten Datenbanken verfügen über eine Autowert-Funktion,
die an jeden neuen Datensatz automatisch eine neue Nummer vergibt, sodass die
Datensätze fortlaufend durchgezählt werden. In Abb. 6.3 sehen Sie die normalisierte Form
der Entität Dozent
. Bei der grafischen Darstellung von Datenmodellen werden die
Attribute, die als Identifikationsschlüssel dienen, in geeigneter Form optisch
hervorgehoben.
Die Entität Kurs
ist ähnlich problematisch wie die Entität Dozent
. Vermutlich werden
mehrere Kurse mit derselben Bezeichnung angeboten und finden vielleicht sogar parallel
statt. Also brauchen wir auch für die Entität Kurs
einen Identifikationsschlüssel. Am
leichtesten lösen wir dieses Problem, indem wir für jeden Kurs eine eigene Kursnummer
vergeben. Da die meisten Kurse sowieso schon eine Nummer haben, brauchen wir uns
hier nicht übermäßig verausgaben. Wenn Sie versuchen, einen Datenbestand zu
normalisieren, werden Sie auf Informationen stoßen, die Sie bei der Erstellung des
Ausgangsdatenmodells zunächst außer Acht gelassen haben, oder auf andere Daten, die
sich nun als plötzlich sehr nützlich erweisen und darum in die Datenbank aufgenommen
werden sollten. Mit der Vergabe einer Kursnummer ist die Entität Kurs
in der ersten
Normalform, zu sehen in Abb. 6.4.
Abbildung 6.3: Die Entität Dozent
in der ersten Normalform
Abbildung 6.4: Die Entität Kurs
wird über die Kursnummer eindeutig identifiziert.
In unserem Ausgangsdatenmodell waren die Kursteilnehmer nur »Menschen zweiter
Klasse«, denn der einzige Weg, über die Teilnehmer etwas herauszufinden, führte über die
Entität Dozent
. Erfassen wir die Teilnehmer nun in einer eigenen Entität und damit in
einer eigenen Tabelle, können wir mit jedem Datensatz noch zusätzliche Informationen
speichern. Wie bei der Entität Dozent
haben wir auch hier das Problem, dass Teilnehmer
denselben Namen haben können, und die Wahrscheinlichkeit ist sogar größer, da es ja
mehr Teilnehmer als Dozenten gibt. Wie bei den Dozenten vergeben wir auch für die
Teilnehmer Nummern, um sie eindeutig identifizieren zu können. Heraus kommt die
erste Normalform der Tabelle Teilnehmer
, zu sehen in Abb. 6.5.
Abbildung 6.5: Wie bei der Entität Dozent
können auch bei der Entität Teilnehmer
Namen mehrfach vorkommen.
Die letzte Entität, die adressiert werden muss, ist die Entität Raum
. Mit unserer
gegenwärtigen Festlegung haben wir Glück. Da sich ein Raum über seine Raumnummer
eindeutig von allen anderen Räumen des Gebäudes unterscheiden lässt, sind wir schon am
Ziel unserer Bestrebungen. Sollte sich die Volkshochschule jedoch entschließen, ihre
Kurse auf mehrere Veranstaltungsorte zu verteilen, bekämen wir Schwierigkeiten. Wir
wollen es aber heute nicht allzu schwer machen und gehen darum davon aus, dass alle
Kurse im selben Gebäude stattfinden. Eine vielleicht nicht ganz realistische Annahme,
darum können Sie im Übungsteil zu dieser Lektion das Datenmodell dahingehend
anpassen, dass die Kurse auf mehrere Veranstaltungsorte verteilt werden. Die endgültige
Form der Entität Raum
sehen Sie in Abb. 6.6.
Abbildung 6.6: Die Entität Raum
ist bereits in der Normalform.
Nachdem alle Entitäten in die erste Normalform gebracht sind und eindeutige Identifikationsschlüssel besitzen, können wir daran gehen, die Beziehungen zwischen den einzelnen Entitäten zu definieren. So erhalten wir ein klareres grafisches Datenmodell und können eventuelle Inkonsistenzen besser lokalisieren.
Nehmen wir zum Beispiel die Entitäten Kurs
und Raum
. Sehen Sie sich die verschiedenen
Entitäten an und versuchen Sie, die einzelnen Entitäten mit dem Verb »hat« in Beziehung
zu setzen. Im Falle von Kurs
und Raum
ergäbe das: »Jeder Kurs hat einen Raum«. Auf
diesem Weg haben wir unsere erste Beziehung ermittelt.
Nach unserem Datenmodell lassen sich die nachstehend aufgeführten Beziehungen ermitteln (grafisch dargestellt in Abb. 6.7):
Abbildung 6.7: Die Beziehungen innerhalb unseres aktuellen Datenmodells. Nicht unproblematisch!
Raum/Kurs
(1:n) - In einem Raum können mehrere Kurse stattfinden.
Dozent/Kurs
(1:n) - Ein Dozent kann mehrere Kurse geben.
Teilnehmer/Kurs
(m:n) - Ein Teilnehmer kann mehrere Kurse belegen. Ein Kurs
kann mehrere Teilnehmer haben.
Mit der Teilnehmer/Kurs-Beziehung sind wir etwas in die Bredouille geraten. Es handelt
sich hier um eine Viele-zu-viele-Beziehung, die wir in zwei getrennte Eins-zu-viele-
Beziehungen aufbrechen müssen. Hierzu müssen wir eine dritte Entität einfügen, die
zwischen den beiden anderen Entitäten sozusagen den Vermittler spielt. Diese neue
Entität muss zu den beiden anderen Entitäten in einer 1:n-Beziehung stehen. Im Falle der
Entitäten Teilnehmer
und Kurs
könnten wir die Entität Platznummer
einführen und damit
den Platz des Teilnehmers in einem bestimmten Kurs definieren.
Teilnehmer/Platznummer
(1:n) - Ein Teilnehmer kann mehrere Platznummern in
verschiedenen Kursen haben.
Kurs/Platznummer
(1:n) - Ein Kurs kann mehrere Platznummern für Teilnehmer
haben.
Abbildung 6.8: Alle Entitäten sind nun in die erste Normalform gebracht und über 1:n-Beziehungen miteinander verknüpft.
Damit lösen wir unser m:n-Problem, denn ein Sitzplatz kann nicht von mehr als einem Teilnehmer gleichzeitig besetzt werden, noch können Sitzplätze von mehreren Kursen auf einmal belegt werden. Wir fügen die neue Entität mitsamt ihren Beziehungen in unser grafisches Datenmodell ein und erhalten das in Abb. 6.8 gezeigte Schema.
Na, das war jetzt doch Einiges an Gehirnakrobatik. Sie fragen sich vielleicht, was der ganze Aufwand soll, nur um eine simple Datenbank zu entwerfen. Aber - so lehrt die Erfahrung - die Mühe, die Sie in die Entwurfsphase stecken, erspart Ihnen später Einiges an Zeit und Arbeit. Ohne Fleiß gibt's nun mal keinen Preis.
Der Weg zur ersten Normalform war hie und da mit Steinen gepflastert. Im nächsten Schritt müssen wir die Entitäten in die zweite Normalform bringen. Um die Bedingungen für die zweite Normalform zu erfüllen, müssen die Entitäten in einer Form definiert werden, die ermöglicht, dass die einzelnen Attribute (mit Ausnahme des Identifikationsschlüssels) allein vom jeweiligen Identifikationsschlüssel abhängen.
Kommen z.B. bestimmte Attribute in verschiedenen Datensätzen einer Entität mehrfach vor, sind also identisch, so sind sie nicht vollständig von einem Identifikationsschlüssel abhängig. Ein Weg, das herauszufinden, ist sich zu fragen: »Wenn sich ein Datum in diesem Datensatz ändert, muss ich es dann in anderen Datensätzen dieser Entität ebenfalls ändern?« Überprüfen Sie unter diesem Gesichtspunkt die verschiedenen Attribute der Entitäten, die wir in unserem Datenmodell aufgestellt haben. In allen Fällen sind sämtliche Attribute von einem Identifikationsschlüssel abhängig. Jeder Datensatz einer Entität kommt nur einmal vor.
Bringt man Daten in die zweite oder dritte Normalform, stößt man immer wieder mal auf
Daten, die noch nicht in das Datenmodell integriert sind. Die dritte Normalform bietet
weniger Verständnisschwierigkeiten als die zweite. Um die Bedingungen für die dritte
Normalform zu erfüllen, muss die Entität bereits in die zweite Normalform gebracht sein
und darf keine Attribute enthalten, die in irgendeiner Form voneinander abhängig sind
(mit Ausnahme vom ID-Schlüssel). Solche Fälle lassen sich gewöhnlich leicht einkreisen.
So gibt es z.B. bei unserer Entität Kurs
eindeutig Probleme mit der dritten Normalform.
Die Entität Kurs
hat die Attribute Name
und Thema
. Diese beiden Attribute hängen
offensichtlich zusammen, also müssen wir die Entität modifizieren, um sie in die dritte
Normalform zu bringen. Zu diesem Zweck führen wir eine neue Entität Thema
ein, die den
Namen des Kurses und sein Thema aufnimmt. Da mehrere Kurse dieselbe Bezeichnung
und dasselbe Thema haben können, besteht zwischen Thema
und Kurs
eine 1:n-Beziehung.
Abb. 6.9 zeigt das endgültige Datenmodell.
Unser Datenmodell umfasst nun die folgenden Entitäten:
Dozent - persNr, vname, nname, status, gehalt
Kurs - kursNr, zeit, level
Thema - name, thema
Teilnehmer - teilnNr, vname, nname, alter, level
Platznummer - sitzNr
Raum - raumNr, plaetze, einrichtung
Diese Entitäten und die Beziehungen, die zwischen ihnen bestehen, sind alles, was Sie brauchen, um Datenbanken für dynamische Websites anzulegen.
Haben wir unser Datenbankmodell auf dem Papier konzipiert, ist die Datenbank selbst damit noch nicht vollständig definiert. Wir müssen unsere Informationen noch irgendwie aufbereiten, um die physikalische Datenbankstruktur anlegen zu können. Diese Struktur ist den Entitäten nicht unähnlich, die wir definiert haben, aber wir müssen noch Mittel und Wege finden, wie wir die Beziehungen zwischen ihnen beschreiben. Die Definition mehrerer Tabellen mit den gewählten Attributen reicht offensichtlich nicht aus, um diese Tabellen untereinander zu verknüpfen. Hierzu müssen wir uns noch mit dem Konzept der Schlüssel auseinander setzen.
Abbildung 6.9: Nun ist unser Datenmodell in der dritten Normalform.
Um unser Datenbankmodell zu komplettieren, brauchen wir noch so genannte Schlüssel, von denen es zwei verschiedene Typen gibt. Der erste ist der so genannte Primärschlüssel, den wir schon kennen gelernt haben, als wir den Identifikationsschlüssel der einzelnen Entitäten definiert haben. Über den Primärschlüssel kann das Datenbanksystem Datensätze eindeutig erkennen.
Mit der Definition eines eigenen Schlüssels für jeden Datensatz haben wir eigentlich nichts anderes getan, als jeder Entität ein weiteres, eindeutiges Feld hinzuzufügen. Es wäre aber auch eine andere Vorgehensweise denkbar, vor allem dann, wenn eine Entität auf der »n-Seite« einer 1:n-Beziehung steht. Man kann nämlich verschiedene Attribute einer Entität sozusagen gruppieren und als Primärschlüssel definieren. Ein Beispiel: Der Nachname einer Person kann mehrfach vorkommen und ist daher kein eindeutiges Merkmal, könnte es aber in Verbindung mit anderen Attributen werden. So ist es höchst unwahrscheinlich, dass der Name einer Person in Kombination mit Anschrift und Geburtsdatum nicht eindeutig ist.
Primärschlüssel haben wir also schon verwendet und sie stellen auch kein Verständnisproblem dar. Die zweite Art von Schlüssel, die wir brauchen, ist der so genannte Fremdschlüssel. Mit ihm kommt Bewegung in unsere träge Datenmasse, denn er definiert die Beziehungen zwischen den verschiedenen Entitäten. Der Fremdschlüssel ist nichts anderes als der in einer Entität gespeicherte Primärschlüssel einer anderen Entität. Er macht die Beziehung zwischen diesen beiden Entitäten sozusagen amtlich.
Für alle Beziehungen muss auf der »n-Seite« einer Beziehung ein Fremdschlüssel festgelegt werden. Für unser Datenmodell haben wir die folgenden Beziehungen definiert:
Raum/Kurs
(1:n) - In einem Raum können mehrere unterschiedliche Kurse stattfinden.
Dozent/Kurs
(1:n) - Ein Dozent kann mehrere Kurse geben.
Teilnehmer/Platznummer
(1:n) - Ein Teilnehmer kann mehrere Platznummern haben.
Kurs/Platznummer
(1:n) - Ein Kurs hat mehrere Plätze für Teilnehmer.
Thema/Kurs
(1:n) - Ein Thema kann in mehreren Kursen behandelt werden.
In all diesen Fällen muss die »n-Seite« den Primärschlüssel der »1-Seite« erben. Wird ein
Primärschlüssel in einer anderen Tabelle gespeichert als in der, in der er definiert wurde,
spricht man von ihm als Fremdschlüssel. So müssen wir z.B. in der Entität Kurs
das
Attribut Raumnummer
mit speichern, das wir von der Entität Raum
übernehmen. Damit
werden die 1:n-Beziehungen der Entität komplettiert. Diesen Schritt müssen wir für alle
anderen Entitäten ebenfalls durchführen.
Wenn Sie möchten, können Sie das jetzt durchspielen. Abb. 6.10 zeigt das endgültige grafische Modell unserer Datenstruktur. An diesem Punkt haben wir die Daten so weit geordnet, dass wir sie als saubere SQL-Datenbank anlegen können.
Abbildung 6.10: Das endgültige Datenbankmodell
In einer späteren Lektion (Tag 12, »Komplexe Datenbankabfragen«) werden Sie etwas über die Datenbank-Abfragesprache SQL lernen. Im Moment wollen wir uns mit einem Blick darauf begnügen, wie unser Datenbankmodell in SQL aussieht. Die Entitäten unseres Modells bilden die Tabellen der Datenbank, die einzelnen Attribute werden zu den Feldern der Tabelle. Es dürfte nicht schwer fallen, die Bezüge zwischen Modell und SQL nachzuvollziehen.
create table raumTbl (
raumNr int not null,
plaetze int,
einrichtung varchar(50),
primary key (raumNr)
)
create table dozentTbl (
persNr int not null,
vname varchar(25),
nname varchar(25),
status varchar(50),
gehalt int,
primary key (persNr)
)
create table kursTbl (
kursNr int not null,
thema varchar(50),
persNr int,
raumNr int,
time time,
level int,
primary key (kursNr)
)
create table themaTbl (
name varchar(50) not null,
thema varchar(250),
primary key (name)
)
create table teilnTbl (
teilnNr int not null,
vname varchar(25),
nname varchar(25),
alter int,
level int,
primary key (teilnNr)
)
create table platznrTbl (
sitzNr int not null,
teilnNr int,
kursNr int,
primary key (sitzNr)
)
Im Grunde ist daran nichts Geheimnisvolles. Interessant ist ein Vergleich des endgültigen Datenbankmodells mit unserem Ausgangsmodell. Statt einer einzigen Tabelle mit einem Wust von teils redundanten Daten haben wir nun ein logisch strukturiertes Modell von sechs Tabellen.
Um dynamische, datenbankgestützte Websites zu erzeugen braucht es etwas mehr als nur UltraDev zu öffnen und dann einfach loszulegen. Sie sollten reichlich Zeit auf die Planungsphase verwenden. Es ist effektiver, zunächst einmal auf einem Blatt Papier die komplette Datenbankstruktur zu entwerfen, statt gleich am Programmcode zu stricken und dann festzustellen, dass man die Datenbank nochmal völlig neu konzipieren muss.
Bestimmte HTML-Dokumente lassen sich besonders gut dynamisch machen:
Eine Sitemap zu zeichnen und die künftige Site auf diese drei Kategorien hin zu überprüfen sind die ersten Schritte in der erfolgreichen Planung einer dynamischen Webanwendung.
Haben Sie alle Informationen vorliegen, die Sie zur Erstellung einer Site benötigen, können Sie ein Datenmodell entwerfen. Das Verfahren, mit dem das Datenmodell um redundante Daten bereinigt wird, bezeichnet man als Normalisierung.
Es gibt drei Normalisierungsschritte, die man einhalten sollte, damit das Datenmodell problemlos in eine tatsächliche Datenbank übersetzt werden kann.
Die erste Normalform definiert die Entitäten, mit denen das Modell arbeitet, sowie die entsprechenden Attribute. Damit wird ferner sichergestellt, dass die Attribute nur einmal vorkommen und sich wiederholende Attribute in einer eigenen Tabelle abgelegt werden. Sind die Entitäten definiert, muss geklärt werden, welche Beziehungen zwischen ihnen bestehen. Beziehungen werden graduell eingestuft: 1:1, 1:n, m:n.
Die zweite Normalform setzt voraus, dass die Daten bereits in die erste Normalform gebracht sind. Ferner dürfen Attribute ausschließlich vom Identifikationsschlüssel des jeweiligen Datensatzes abhängig sein.
Für die dritte Normalform müssen die Entitäten in der zweiten Normalform vorliegen. Zusätzlich muss eine weitere Anforderung erfüllt sein. Hängen Attribute nicht ausschließlich vom Identifikationsschlüssel, sondern von anderen Attributen ab, müssen sie in einer eigenen Tabelle abgelegt werden, damit die Bedingungen für die dritte Normalform erfüllt sind.
Der letzte Schritt im Datenbankentwurf besteht in der Anlage der Datenbankstruktur selbst. Die Struktur der Datenbank beruht auf dem fertig ausgearbeiteten Datenbankmodell, muss aber noch um die Informationen ergänzt werden, in welcher Beziehung die Entitäten zueinander stehen.
Frage:
Was ist der Hauptgrund für den Einsatz von datenbankgestützten Websites?
Antwort:
Das Hauptargument für eine Datenbankanbindung ist die Effizienz. Allzu oft ist
das Argument für den Einsatz einer bestimmten Technologie die bloße
Verfügbarkeit, nicht tatsächliche praktische Erfordernisse oder Notwendigkeiten.
Sie sollten Datenbanken nur dann einsetzen, wenn es die Website um sinnvolle
Funktionen bereichert und die Betreuung vereinfacht - nicht, weil es gerade
»hipp« ist.
Frage:
Wie kann man mit einer Datenbank eine leichter bedienbare Oberfläche für eine
Webseite erstellen, als das mit HTML-Mitteln möglich wäre?
Antwort:
Vielleicht wundern Sie sich, wieso eine datenbankgestützte Website
»pflegeleichter« sein soll als eine auf reinem HTML-Code basierende Site. Wenn
Sie eine Datenbank wie MS Access verwenden oder eine Programmiersprache wie
RealBASIC, können Sie eine Eingabemaske erstellen, die genauso leicht zu
bedienen ist wie eine beliebige Office-Anwendung.
Frage:
Kann ich Datenbanken auch erstellen, ohne die Daten vorher zu normalisieren?
Antwort:
Das geht zwar, aber ich würde es nicht empfehlen. Die Normalisierung von Daten
führt zu einem effizienten Datenmodell ohne Redundanzen. In manchen Fällen
ist ein gewisses Maß an Redundanz vertretbar, und Sie können auf den Prozess der
Normalisierung verzichten. Wollen Sie aber professionelle Sites erstellen, möchte
ich Ihnen dringend raten, sich die Zeit zu nehmen und die Daten sauber zu
normalisieren.
Frage:
Mit welchen Problemen muss ich rechnen, wenn ich Daten nicht normalisiere?
Antwort:
In diesem Fall müssen Sie damit rechnen, dass Sie wirklich viel Zeit damit
aufwenden müssen, um Ihren Datenbestand zu aktualisieren. Nicht normalisierte
Datenbanken weisen Redundanzen auf. Somit ist es unmöglich, exakte
Suchabfragen zu formulieren. Eine Aktualisierung ist ebenfalls sehr aufwändig, da
Sie pro Änderung immer mehrere Datensätze aktualisieren müssen. Bei fünf oder
sechs Datensätzen ist das noch kein Problem. Aber, wie Sie sich vorstellen können,
wächst die benötigte Zeit mit der Anzahl der Datensätze.
Der Workshop dient dazu, den gelesenen Stoff mithilfe von gezielten Fragen und Übungen zu vertiefen. Die Antworten finden Sie in Anhang A, »Quiz-Antworten«.