package ejb; import java.io.Serializable; import javax.ejb.Local; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import common.Artikel; import service.ArtikelDao; @Stateless(name = "ArtikelDao") @Local(service.ArtikelDao.class) public class ArtikelDaoBean implements ArtikelDao, Serializable { @PersistenceContext(unitName = "containerPersistence") private EntityManager entityManager; public void delete(Artikel artikel) { entityManager.remove(artikel); } public Artikel getById(Long id) { return entityManager.find(Artikel.class, id); } public void save(Artikel artikel) { entityManager.persist(artikel); } public void update(Artikel artikel) { entityManager.merge(artikel); }
Der Name dieses Entwurfsmusters ist Programm: Es schlägt vor, Klassen zu erstellen, deren einzige Aufgabe es ist, Daten dauerhaft zu speichern oder dauerhaft gespeicherte Daten zur Verfügung zu stellen.
Eine DAO-Klasse enthält Methoden wie
Das Objekt der Begierde ist in unserem Beispiel ein Artikel. Seine einzige Aufgabe ist es, Daten strukturiert aufzunehmen, die dauerhaft gespeichert werden sollen.
In der DAO-Schnittstelle werden so genannte Business-Objekte verwendet wie beispielsweise Kunde oder Bestellung. Die Namen der DAO-Klassen werden anhand der Business-Objekte hergeleitet. Kunden-Objekte werden in der KundenDao, Bestellung-Objekte in einer BestellungDao abgespeichert.
Die Benutzung des DAO-Patterns wird anhand des Kommunikationsdiagramms der Abbildung 1 diskutiert. Als Beispiel wird ein fiktiver Bestellvorgang in einer JEE-Architektur skizziert.
Der Client verfügt über Kunden- und Artikelnummer und kennt die zu bestellende Menge. Mit diesen Informationen wird der Bestellvorgang auf den Weg geschickt. Die BestellBean nimmt die Nachricht entgegen und delegiert sie an einen Bestellservice. Dieser wird passend zur Kunden- und Artikelnummer die entsprechenden Kunden und Artikel aus der Datenbank laden.
Dazu verwendet der Service Instanzen von KundenDao und ArtikelDao. Darauf wird der Service ein Bestell-Objekt erzeugen und dieses mit Hilfe einer BestellungDao in der Datenbank ablegen.
Anhand des Kommunikationsdiagramms (Abbildung 1) lassen sich wesentliche Vorteile der Verwendung des Entwurfsmusters darstellen. Ein Service kann mehrere DAO-Objekte in Anspruch nehmen. Durch die Separation von Service und DAO ist die Wiederverwendbarkeit des Codes für den Zugriff auf die Daten gewährleistet.
Die Dienstleistung der DAO-Klassen wird offensichtlich angeboten: Sind Informationen zu einem Artikel oder einem Kunden erforderlich, welche Klasse muss eingesetzt werden? Die ArtikelDao und KundenDao, natürlich.
Offensichtlich ist auch, dass die DAO-Klassen eine Schicht bilden. Oberhalb dieser Schicht, zu den Service-Klassen hin, werden Informationen immer als Objekt (wie Kunde oder Artikel) behandelt. Aspekte der Datenbank bleiben verborgen.
In Abbildung 2 wird verdeutlicht, wie sich das DAO-Pattern in die Business Layer eingliedert. In der Business Layer wird die Geschäftslogik umgesetzt. Es wird von einer JEE-Architektur ausgegangen. Die Business Layer ist als Anwendung auf dem Application-Server deployed.
Durch den Einsatz des DAO-Patterns ist es möglich, die Business Layer weiter zu gliedern. Die DAO-Klassen sind dabei das Herzstück der Persistence Layer. In der Regel verwenden diese ein Persistence-Framework wie beispielsweise Hibernate oder eine Implementierung der Java Persistence API. Doch die Implementierung ist der Service Layer nicht bekannt – sie kennt nur die Schnittstellen der DAO-Klassen.
Die Service Layer implementiert die eigentliche Geschäftslogik. Sie ist durch die Persistence Layer aller Aufgaben der Datenpersistenz entledigt und kann sich dadurch auf ihre Kernaufgabe konzentrieren.
Zum Client hin sorgt eine Communication Layer (z. B. in Form einer Session Facade) dafür, dass die Kommunikation zwischen Client und Server problemlos verläuft. Schnittstellen können dadurch stabil gehalten werden, Services können in gewissem Umfang entkoppelt von der Client-Schnittstelle (weiter-)entwickelt werden. Exceptions werden mundgerecht an den Client weitergereicht.
Die Abstraktion der Persistenz führt dazu, dass die DAO-Schicht einfach austauschbar ist. Zu diesem Zweck sind DAO-Interfaces zu definieren. Die Austauschbarkeit beflügelt den Entwicklungs- und Testprozess, indem einfache Varianten der DAO-Klassen (so genannte Mock-Klassen) eingesetzt werden.
Performance-Probleme stehen nicht selten in Zusammenhang mit Datenbankzugriffen. Die Kapselung dieser Zugriffe ist eine gute Voraussetzung dafür, dass sich Spezialisten genau auf diese Aspekte konzentrieren können.
Für die Implementierung sind noch wesentliche Aspekte nicht angesprochen worden:
Die Beantwortung dieser Fragen richtet sich sehr nach der Umgebung, in der die Implementierung erfolgt. Unabhängig davon sollte eine Lösung aber die folgenden Aspekte berücksichtigen:
Da die Implementierung von DAO zu den Standardaufgaben der Anwendungsentwicklung gehört, gibt es Standardlösungen. Vielfach erprobt ist der Einsatz des Java-Enterprise-Standards oder aber des Spring-Frameworks [2].
Im Folgenden wird die Implementierung von DAOs in einer Java-Enterprise-Architektur weiter verfolgt.
Die Geschäftslogik ist in einer JEE-Architektur in einem EJB-Container auszuführen. Dieser Container stellt unter anderem genau die erforderliche Infrastruktur für die Implementierung des DAO-Entwurfsmusters zur Verfügung: Er verwaltet sowohl die Verbindung zur Datenbank als auch Transaktionen. In Abbildung 3 sind die Aufgaben des EJB-Containers skizziert:
Er erzeugt die DAO-Beans und injiziert diesen einen Entity Manager. Mit diesem kann direkt ein objekt-relationaler Zugriff auf die Datenbank erfolgen. Auch die BestellBean wird vom EJB-Container erzeugt und mit den erforderlichen DAOs ausgestattet.
Die Transaktionssteuerung kann und sollte der EJB-Container ebenfalls übernehmen (Container Managed Transaction). Ruft ein Client eine Service-Methode auf, so kümmert sich der EJB-Container um die Transaktion.
In dieser Infrastruktur kann sich jede Schicht auf ihre Kernaufgabe konzentrieren. Die Implementierung des DAO-Patterns wird stark vereinfacht. In Abbildung 4 ist sie exemplarisch für die Klasse ArtikelDaoBean dargestellt.
Der Entity Manager stellt die erforderlichen Methoden unmittelbar zur Verfügung. Doch das wird sich im Laufe der Zeit ändern: In der Regel kommen umfangreichere Methoden dazu, wenn die Business Objekte Kollektionen anderer Objekte enthalten oder aber spezielle Datenbanksuchen erforderlich sind.
Schwieriger zu deuten sind die Annotations zu Beginn des Quellcodes von Abbildung 4. Damit der EJB-Container für DAOs genutzt werden kann, müssen diese als EJBs implementiert werden. Die Annotation @Stateless konfiguriert diese Klasse als Stateless-Session-Bean.
DAOs werden durch @Local als lokale EJB konfiguriert: Der Client darf keinen direkten Zugriff auf diese Beans haben. So wird verhindert, dass ein Client seine eigene Applikationslogik implementiert.
Das Entwurfsmuster Data Access Object gehört für die Implementierung von Geschäftslogik mit Datenbankanschluss zum Stand der Technik. Die Herausforderung ist weniger die Entwicklung der Data Access Klassen sondern vielmehr die Einrichtung der erforderlichen Infrastruktur. In unseren JEE-Seminaren [4] erfahren Sie mehr zur Implementierung des DAO-Patterns. Gern unterstützen wir Sie auch beim Entwurf und der Implementierung ihres Entwicklungsprojekts.