Autorenarchiv

Vererbung in Hibernate

Freitag, 17. September 2010

Beim Design von Datenbanken stellen wir häufig fest, das Gruppen von Attributen in mehreren Entitäten vorkommen. Aus objektorientierter Sicht würden man hier auf eine Vererbung hinarbeiten. Leider sind solche Konstrukte in der Datenbank nicht direkt möglich. Hibernate bietet uns hier die Möglichkeit der Vererbung.

Als Beispiel nehmen wir an, das zu unseren Kunden Firmen und Personen gehören und alle über Bankdaten verfügen:

Beispiel: Komponenten im DB-Design

In Java würde diese Vererbung wie folgt aussehen:

    @Entity
    @Table(name = "account_holders")
    @Inheritance(strategy = InheritanceType.JOINED)
    public abstract class AccountHolder {
        private String bankName;
        private String bankCode;
        private String accountNumber;
        ...
    }
 
    @Entity
    @Table(name = "persons")
    public class Person extends AccountHolder {
        private String firstName;
        private String lastName;
        ...
    }
 
    @Entity
    @Table(name = "companies")
    public class Company extends AccountHolder {
        private String name;
        ...
    }

Neben der Vermeidung von doppelten Datenstrukturen in der Datenbank, zeigt sich hier ein weiterer interessanter Aspekt: Das Laden abstrakter Klassen!

Wenn wir im oben genannten Beispiel eine Liste aller Kunden (Personen und Firmen) mitsamt ihren Bankdaten laden wollen, reicht ein einziger Aufruf:

    List<AccountHolder> clients = new AccountHolderDAO().getList();

Hiermit kann man viel Freude haben, wenn man alle Aspekte im Blick hat: Da Hibernate bei Aufruf noch nicht weiß, welche Daten für eine Instanz erforderlich sind, wird ein Join über die Tabelle der abstrakten Klasse selbst und der Tabellen aller Kindklassen erstellt. Dies kann bei einer tiefen oder weitläufigen Vererbungshierarchie durch große Joins die Performance spürbar drücken. Von einer Verwendung für häufig angehängte Daten würde ich daher Abstand nehmen.


Thomas Bader


Firefox-Plugin: HTML Validator unter Debian/Linux

Donnerstag, 22. April 2010

Mit jahrelanger Entwicklung von J2EE-Anwendungen gewöhnt man sich an die einen Dinge und gewinnt andere Dinge lieb:

  1. Fast alle HTML-Seiten im Internet sind nicht W3C konform.
  2. Es ist gut wenn man einen Validator hat, dies zu erkennen und es besser zu machen.

Um Probleme im HTML-Code sofort zu erkennen verwende ich das Firefox-Plugin: HTMLValidator.

Leider ist die Verwendung unter Linux seit geraumer Zeit etwas schwierig geworden. Zum Einen kann man das Plugin für Linux nicht mehr über Mozilla bekommen, sondern muss das Plugin direkt bei Marc Guery herunterladen; zum Anderen findet das Plugin verschiedene Pakete nicht mehr.

Glücklicherweise ist das Problem lösbar, wenn auch nicht offentsichtlich.

Schritt 1:
Im Regelfall fehlen unter Linux bestimmte Pakete. Dies kann man leicht nachinstallieren, wie es in der Anleitung beschrieben steht.

libstdc++5 
libnspr4

Vielleicht läuft das Plugin nun. Wenn nicht folgt …

Schritt 2:
Nun sollten wir prüfen, welche Bibliotheken eigentlich noch fehlen. Dazu wechseln wir in das Verzeichnis, in dem das Plugin installiert wurde und rufen dort den ldd-Befehl, mit dem wir die fehlenden Bibliotheken identifizieren können:

cd <home.verzeichnis>/mozilla/firefox/<profil.verzeichnis>/extensions/{3b56bcc7-54e5-44a2-9b44-66c3ef58c13e}/components
ldd libnstidy.so

Ich würde an dieser Stelle erwarten, das die Bibliothek libxpcom.so nicht gefunden werden kann. Es gab hier unter Debian anscheinend eine Umbenennung der Pfade. Daher müssen wir dem System nun definieren, wo die Bibliotheken zu finden sind:

ln -s /usr/lib/xulrunner-1.9/libxul.so /usr/lib/libxul.so
ln -s /usr/lib/xulrunner-1.9/libxpcom.so /usr/lib/libxpcom.so

Natürlich sollte der Name des XUL-Verzeichnisses vorher geprüft werden.

Jetzt könnte das Plugin theoretisch laufen. Wenn dem aber nicht so ist folgt …

Schritt 3:
Deinstalliere das Plugin und installiere es danach erneut.

Nun sollte das Plugin einwandfrei funktionieren und anzeigen welche HTML-Seiten W3C-konform sind und welche nicht.


Thomas Bader


Schnellere Web-Anwendungen

Montag, 04. Januar 2010

Bei der Entwicklung von Web-Anwendungen ist die Performance in der Regel die letzte Frage, die gestellt wird. Der Fokus liegt im Regelfall auf der Umsetzung der Anforderungen.

Die Geschwindigkeit der Anwendung sollte aber früh mit eingeplant werden, da die Antwortzeiten darüber entscheiden, ob eine Anwendung als gut oder schlecht wahrgenommen wird. Dauert das Laden des gewünschten Inhalts zu lange, wird die Anwendung nie die Akzeptanz der Benutzer erfahren. Spontane Benutzer können sogar die Anwendung verlassen, weil sie die Anwendung / den Link als tot betrachten. Wer wartet schon 15 Sekunden auf eine Web-Seite!?

Die Geschwindigkeit einer Anwendung wird durch viele Parameter bestimmt. Während Anwendungen serverseitig meistens aufgrund einer hohen Anzahl von Datenbankabfragen lahmen, ist das Problem clientseitig komplexer, lässt sich aber auf 2 grundlegende Aussagen zusammenfassen:

  • Größe der geladenen Objekte (HTML, Bilder, CSS, JavaScript)
  • Anzahl der eingebundenen Objekte (Bilder, CSS, JavaScript)

Die Größe der Objekte bedingt eine längere Ladezeit und die Anzahl der Objekte führt zu einer Vielzahl von Anfragen an den Server. Jede Anfrage an den Server erzeugt einen eigenen Overhead.
Erst wenn alle Objekte vollständig geladen sind, kann der Inhalt vollständig und korrekt angezeigt werden.

Schritt 1: Komprimierung
Die Größe fast jeden Inhalts kann durch eine Komprimierung verringert werden. Die Komprimierung erfolgt am besten durch den Webserver. Beim Apache kann dies das Modul mod_deflate übernehmen.

Schritt 2: Caching
Das Meiste, was für die Anzeige der Oberfläche einer Web-Anwendung benötigt wird, kann gecached werden. Einzig die dynamisch generierten Objekte (im Regelfall nur das HTML), dürfen nicht gecached werden.
Der Server kann den Client durch durchgängiges Setzen von Header-Informationen unterstützen, die angeben wie lange das Objekt gültig ist. Auch hierfür gibt es beim Apache ein entsprechendes Modul: mod_expires

Mit diesen beiden rudimentären Schritten läßt sich die Performance schon spürbar verbessern, da weniger Objekte vom Server übertragen werden und diese nicht größer als notwendig sind.
Dies ist natürlich noch lange nicht alles, sollte aber bei geringem Aufwand den größten Nutzen erzielen.

Zur Unterstützung der Optimierung einer Webseite kann ich Firebug und YSlow (2 Plugins für Firefox) empfehlen.
Während man mit Firebug die einzelnen Anfragen an den Server mit den Headern für den Serverrequest und -response einsehen kann, gibt YSlow weitergehende Tipps zur Optimierung einer HTML-Seite.

Geschwindigkeit ist nicht alles, aber: “Performance rules!”


Thomas Bader


PostgreSQL-Funktionen mit ANT einspielen

Mittwoch, 12. August 2009

Um eine Datenbank auf dem aktuellen Stand zu halten, bietet sich ANT mit dem Task sql an. Hiermit ist es ein leichtes viele SQL-Skripte effektiv in die Datenbank einzuspielen:

<sql
    driver="org.database.jdbcDriver"
    url="jdbc:database-url"
    userid="sa"
    password="pass"
    src="data.sql"/>

Der Lösung so nah

Dies funktioniert soweit sehr gut, es sei denn man versucht Funktionen in die Datenbank einzuspielen. ANT kann leider nicht mit den Semikoli (;) in der Funktion richtig umgehen; so wird davon ausgegegangen das jedes Semikolon ein Statement beendet. Dies trifft beim Einspielen einer Funktion natürlich nicht zu. Hierfür bietet ANT eine schnelle Lösung mit dem Attribute “delimiter” am sql-Task. In dem folgenden Beispiel wird der Default-Delimiter (;) durch “$$” ersetzt.

<sql
    driver="org.database.jdbcDriver"
    url="jdbc:database-url"
    userid="sa"
    password="pass"
    src="data.sql"
    delimiter="$$"/>

Einfacher Fall

Das SQL der einzuspielenden Funktion für PostgreSQL sollte in etwa wie folgt aussehen:

CREATE OR REPLACE FUNCTION hello_world() RETURNS void AS '
BEGIN
    -- Aktionen der Funktion
END;
' LANGUAGE 'plpgsql' $$

Das SQL-Statement erstellt eine Funktion ohne Rückgabewerte, definiert danach die verwendete Sprache und beschliesst das Statement mit dem Delimiter ($$).
Ein kleines aber sehr wichtiges Detail sind hierbei die Hochkomma (‘) hinter dem AS und vor dem LANGUAGE. Auch wenn bei der Verwendung von PgAdmin fast jede beliebiege Zeichenkette dort stehen kann sollte bei der Verwendung von ANT nur das Hochkomma verwendet werden, so das der JDBC den Inhalt der Funktion als Text auffasst und nicht versucht den Inhalt zu interpretieren.

Komplexer Fall

Doch was tun, wenn innerhalb der Funktion Texte verwendet werden, die selbst mit einem Hochkomma (‘) eingefasst sind. In diesem Fall muss man darauf achten, das alle Hochkommas innerhalb der Funktion mit einem Hochkomma “escaped” werden.

CREATE OR REPLACE FUNCTION hello_world() RETURNS void AS '
BEGIN
    insert into my_table (text) values (''hello'');
END;
' LANGUAGE 'plpgsql' $$

Thomas Bader