DAOs veraltet - was ist die Alternative?

Mercious

Mitglied
Hallo zusammen,

ich studiere zur Zeit noch und ich habe in diesem Semester eine Veranstaltung, in der jeder ein kleineren Webshop entwickeln muss.
Die Vorgaben sind dazu ausdrücklich: JSP, CSS und plain JS (kein jQuery) im Frontend, Java EE ohne jegliche Frameworks im Backend, JDBC (kein JPA) für die Datenbankanbindung, glassfish als application Server.

Leider habe ich meine bisher einzige, praktische Erfahrung in der Webentwicklung (etwa 2 Jahre) an einem bereits älteren Online Shop gemacht (etwa 7 Jahre).
Dort ist der Backend Code grob in diese drei Elemente aufgeteilt: Controller, welche die Daten, die die zugehörige JSP braucht, sammelt und an die JSP weitergibt. Services, welche komplexere Business-Logik verwalten und DAOs, welche den tatsächlichen Datenbankzugriff abstrahieren (eigentlich auch noch Models als Persistenz-Schicht und ein paar andere Dinge).
Controller rufen also immer Services auf, wenn sie etwas komplexeres brauchen und die Services selber rufen DAOs auf, wenn sie auf die Datenbank zugreifen müssen.

Jetzt meinte der Prof aber zu mir, dass das sehr veraltet und schlecht ist und wir das definitiv anders machen werden. Leider will er erst in der übernächsten Vorlesung preisgeben, wie. Ich würde aber gerne schon weiter machen, da es zeitlich gerade passt.
Daher meine Frage an Euch: Könnt ihr vermuten, was er meint? Was ist besser, was benutzt der moderne Java Webentwickler und wieso?
 

Mercious

Mitglied
Hallo stg,
vielen Dank für deine Antwort!

Ich habe mir den von dir verlinkten Artikel durchgelesen, muss aber zugeben, dass ich daraus nicht so wirklich schlau geworden bin.
Der Artikel betont stark, dass der Business Layer nicht wissen will, wie das Respository an die Daten kommt, die es haben will. Da sehe ich jetzt erstmal kein unterschied, zu einem DAO. Das bietet ja auch ein entsprechendes Interface. Der Aufrufer muss nur wissen, was er haben will.

Einen Unterschied sehe ich dadurch angedeutet, dass es von Interfaces redet. Also wird nur ein Interface definiert, an dem sich der BL orientiert - real kann es mehre Implementierungen dieses Interfaces geben? Hm. Das wäre jetzt schon mal ein Unterschied zu DAOs.

Nun gut, ich hab jetzt erstmal ein Stichwort, mit dem ich mich weiter belesen werde und das werde ich jetzt auch tun. Vielleicht verstehe ich, wenn ich noch ein paar Beispiele sehe, die den Unterschied verdeutlichen.
 

mrBrown

Super-Moderator
Mitarbeiter
Der Artikel betont stark, dass der Business Layer nicht wissen will, wie das Respository an die Daten kommt, die es haben will. Da sehe ich jetzt erstmal kein unterschied, zu einem DAO.
Beide sind dazu da, den Zugriff auf die Datenquelle zu abstrahieren, der Unterschied zwischen beiden ist eher semantischer als technischer Natur.

Repository kommt aus dem DDD-Bereich (oder wurde das vorher schon anders verwendet?), und fungiert einfach nur als eine "Menge" von Entitys (genauer: Aggregate Roots) und sollte die gleiche "Sprache" nutzen, wie die Domäne, und nicht Daten/Datenbank-zentriert sein, wie das oft bei DAO der Fall ist.

Repository ist eher ein "ein Objekt geben und ein Objekt zurückbekommen", DAO oft eher ein "Ein Objekt/Daten speichern, ein Objekt updaten, ein Objekt laden"

Das bietet ja auch ein entsprechendes Interface. Der Aufrufer muss nur wissen, was er haben will.

Einen Unterschied sehe ich dadurch angedeutet, dass es von Interfaces redet. Also wird nur ein Interface definiert, an dem sich der BL orientiert - real kann es mehre Implementierungen dieses Interfaces geben? Hm. Das wäre jetzt schon mal ein Unterschied zu DAOs.
Beide sollten in jedem Fall mit Interfaces umgesetzt sein. Auch bei DAOs ist es Unsinn, direkt die Implementation zu nutzen.
 

Mercious

Mitglied
Beide sind dazu da, den Zugriff auf die Datenquelle zu abstrahieren, der Unterschied zwischen beiden ist eher semantischer als technischer Natur.

Repository kommt aus dem DDD-Bereich (oder wurde das vorher schon anders verwendet?), und fungiert einfach nur als eine "Menge" von Entitys (genauer: Aggregate Roots) und sollte die gleiche "Sprache" nutzen, wie die Domäne, und nicht Daten/Datenbank-zentriert sein, wie das oft bei DAO der Fall ist.

Ich habe mich dazu jetzt noch mal etwas durch SO gewühlt und habe auch in etwa das Gefühl, dass da viel Semantik mit dahinter steckt. Irgendwie hängt es auch stark damit zusammen, wie komplex das Persistieren der BO's in der tatsächlichen Anwendung ist und wie komplex die selber auch sind.
Wenn ich das richtig verstehe, dann gewinnt das Pattern erst richtig an Vorteil, wenn die Dinge halt ziemlich komplex sind.

Alles in allem kann ich ungefähr erahnen, dass ein sauber implementiertes Repository Pattern wohl sauberer und besser ist, als etwas mit DAO "Pattern" zu machen.
Aber sonderlich extrem finde ich es jetzt nicht - also jetzt nicht extremer, als noch JSP als Frontendtechnologie zu verwenden.

Beide sollten in jedem Fall mit Interfaces umgesetzt sein. Auch bei DAOs ist es Unsinn, direkt die Implementation zu nutzen.

Hm, stimmt - die wurden bei uns auch immer in Interface - Implementierung aufgeteilt, jetzt wo du es sagst. So wirklich hab ich das aber auch nie verstanden. An etlichen Stellen trennt man extra in Interface und Impl, obwohl es eigentlich nirgends wirklich mehr als eine Implementierung gibt.
Wieso macht man diese Aufteilung nicht erst, wenn es tatsächlich andere Implementierungen gibt oder diese zu mindestens gut absehbar sind? Man kann doch immer noch im Nachhinein das Interface rausziehen bevor man dann tatsächlich die zweite Implementierung schreibt?
 

mrBrown

Super-Moderator
Mitarbeiter
Alles in allem kann ich ungefähr erahnen, dass ein sauber implementiertes Repository Pattern wohl sauberer und besser ist, als etwas mit DAO "Pattern" zu machen.
Naja, ungefähr so, wie ein vernünftiges Domänen-Orientiertes Design besser ist, als irgendwas hingeklatschtes ;)

Aber sonderlich extrem finde ich es jetzt nicht - also jetzt nicht extremer, als noch JSP als Frontendtechnologie zu verwenden.
Naja, JSP ist eine Technologie von vielen - Technologie ist austauschbar, ohne den Hauptteil anpassen zu müssen ;)
Repositories sind Teil des Entwurfs, und der ist selten beliebig austauschbar und ist ja auch für mehr, als nur die technische Umsetzung da ;)

Hm, stimmt - die wurden bei uns auch immer in Interface - Implementierung aufgeteilt, jetzt wo du es sagst. So wirklich hab ich das aber auch nie verstanden. An etlichen Stellen trennt man extra in Interface und Impl, obwohl es eigentlich nirgends wirklich mehr als eine Implementierung gibt.
Wieso macht man diese Aufteilung nicht erst, wenn es tatsächlich andere Implementierungen gibt oder diese zu mindestens gut absehbar sind? Man kann doch immer noch im Nachhinein das Interface rausziehen bevor man dann tatsächlich die zweite Implementierung schreibt?
Die macht auch Sinn, wenn es keine zweite Implementierung gibt.

Das Interface später rausziehen ist meist unschön, da man dafür oft auch Abhängigkeiten anfassen muss.
Außerdem kann man so das Interface getrennt von der Implementierung entwickeln. Dadurch kann man dann z.B. für Tests direkt mocken (oder auch in der Applikation, solange keine Implementierung vorhanden ist).
Zusätzlich kann man mit Interfaces Abhängigkeiten zwischen Modulen/Packages unidirektional halten,
 

Mercious

Mitglied
Okay, also ich merke mir jetzt einfach mal, dass ich grundsätzlich Dinge wie Services, DAOs (sofern ich diese verwende) und Facaden immer in Interface und Implementierung trenne, da sauberer.

Zu DDD muss ich mir wohl auch mal ein Buch reinziehen, das ist irgendwie auch an mir vorbei gegangen. Microservices bekomme ich gerade voll mit, aber irgendwie scheinen die Ideen und Vorstellungen sehr von DDD inspiriert zu sein, also sollte man sich das vorher eventuell mal verdeutlichen.
[Kann jemand dazu Lektüre (gerne auch auf Englisch) empfehlen?]

Gibt es zu dem Repository Pattern vielleicht zufällig irgendein Open-Source Projekt, wo man das mal in Aktion sehen kann? Das wäre sehr cool.
 

mrBrown

Super-Moderator
Mitarbeiter
Zu DDD muss ich mir wohl auch mal ein Buch reinziehen, das ist irgendwie auch an mir vorbei gegangen. Microservices bekomme ich gerade voll mit, aber irgendwie scheinen die Ideen und Vorstellungen sehr von DDD inspiriert zu sein, also sollte man sich das vorher eventuell mal verdeutlichen.
[Kann jemand dazu Lektüre (gerne auch auf Englisch) empfehlen?]
Domain Driven Desgin von Eric Evans ;)
 

Mercious

Mitglied
Domain Driven Desgin von Eric Evans ;)

Danke, habe ich mir besorgt!

Noch mal eben zum Thema: Der Prof. wollte anscheinend nur auf das Connection Pooling Thema raus. Irgendwie hatte er mir nicht genau zugehört und hatte nur im Code gesehen, dass ich bisher kein Pool verwende, sondern direkt per DirverManager Connections hole.
Im Beispielcode in den Folien macht er die Datenbankzugriffe direkt in den Servlets/Controllern, instanziert also auch da per Resource Injection die DataSource. Ob das besser ist, als DAOs zu schreiben weiß ich jetzt auch nicht.

Eine Frage aber noch: Ich versteh nicht wirklich, wie man in Java EE "container managed objects" erzeugt. Also wie müsste ich meine Klasse "ArticleDAO" deklarieren, damit ich dort z.B. die DataSource per JDNI lookup über die @Resource annotation injecten kann?
Im Servlet funktioniert das, ich nehme an wegen der @WebServlet Annotation. Dort wird das Feld korrekt gefüllt. In meinem DAO bleibt es null, also nehme ich an, dass ich noch irgendwas annotieren oder extenden oder was auch immer muss, damit das DAO auch Teil dieser Resource-Injection Infrastruktur ist. @Stateless habe ich versucht, hatte aber keinen Erfolg. Im Internet ist irgendwie alles nur Durcheinander dazu, komplett verwirrend.
 

mrBrown

Super-Moderator
Mitarbeiter
Noch mal eben zum Thema: Der Prof. wollte anscheinend nur auf das Connection Pooling Thema raus. Irgendwie hatte er mir nicht genau zugehört und hatte nur im Code gesehen, dass ich bisher kein Pool verwende, sondern direkt per DirverManager Connections hole.
Pools sind schon sinnvoll, aber halt völlig unabhängig vom drüber liegenden Zugriffspattern...

Im Beispielcode in den Folien macht er die Datenbankzugriffe direkt in den Servlets/Controllern, instanziert also auch da per Resource Injection die DataSource. Ob das besser ist, als DAOs zu schreiben weiß ich jetzt auch nicht.
...das dagegen klingt nicht sinnvoll, da gehört natürlich eine Schicht zwischen. Kann aber auch der kürze der Folien geschuldet sein.

Eine Frage aber noch: Ich versteh nicht wirklich, wie man in Java EE "container managed objects" erzeugt. Also wie müsste ich meine Klasse "ArticleDAO" deklarieren, damit ich dort z.B. die DataSource per JDNI lookup über die @Resource annotation injecten kann?
Im Servlet funktioniert das, ich nehme an wegen der @WebServlet Annotation. Dort wird das Feld korrekt gefüllt. In meinem DAO bleibt es null, also nehme ich an, dass ich noch irgendwas annotieren oder extenden oder was auch immer muss, damit das DAO auch Teil dieser Resource-Injection Infrastruktur ist. @Stateless habe ich versucht, hatte aber keinen Erfolg. Im Internet ist irgendwie alles nur Durcheinander dazu, komplett verwirrend.
Nutzt ihr CDI?
 

Mercious

Mitglied
Pools sind schon sinnvoll, aber halt völlig unabhängig vom drüber liegenden Zugriffspattern...

Ja, deswegen war ich auch so verwirrt, wieso er jetzt auf einmal DAOs als schlecht bezeichnet hatte. Ich hatte ihn gefragt, ob wir pools verwenden sollen oder nicht. Der Hintergrund war, dass ich zunächst vermutete, dass wir sie der Einfachheit her nicht verwenden, da man diese bei glassfish selber manuell konfigurieren muss (bzw. geht auch per XML) und es somit für ihn erschwert wäre, unseren Code bei sich auf dem lokalen System zu testen. Daher hatte ich es zuerst mit dem DriverManager runter geschrieben und wollte ihn dann fragen, ob wir doch pools verwenden sollen. Er hat wohl nur den Code gesehen, nicht die Frage gehört, und meinte direkt das sei nicht gut so. Naja, wie auch immer.


Weiß ich ehrlich gesagt nicht, das Skript ist noch nicht so weit.
Sofern ich verstanden hab gibt es einen Unterschied zwischen Resource Injection und CDI - ersteres benutzt die @Resource Annotation und letzteres die @Inject Annotation (das soll jetzt nicht der technische Unterschied sein). Für die @Inject Annotation fehlen dem Projekt momentan noch die entsprechenden JAR-Dependencies. Ist das nicht Teil von "Standard" Java EE, das durch glassfish implementiert wird, oder warum fehlt diese JAR? Sofern ich gesehen habe kann man sie einfach manuell hinzufügen, aber ob das jetzt der Voraussetzung "keine Frameworks" widerspricht, kann ich nicht sagen. Ich dachte CDI gehört zu Java EE und glassfish sei eine Vollständige Implementierung dieses Standards, also verstehe ich nicht ganz, wieso dazu die Dependencies fehlen.

Kurz zur Zusammenfassung meiner Verwirrung was dieses Thema angeht:
Bei glassfish konnte ich ein Connection Pool als JDNI-Resource deklarieren. Dem konnte ich einen Namen geben und das "Teil" ist auch auffindbar über Snippet
Java:
new InitialContext().lookup("jdc/myDB")
Das liefert mir meine DataSource Instanz.
Über die Annotation @Resource(lookup="jdbc/myDB") allerdings nicht. Das DAO selber ist momentan nur mit @Stateless annotiert.
Was ich aus Spring kenne, ist dass die Resource-Injection nicht bei Klassen-Instanzen funktioniert, die man mit new() erzeugt. Der ArticleService verwendet mein ArticleDAO und erzeugt dieses momentan noch mit new(), da ich keine Ahnung habe ich es stattdessen injizieren lassen kann (ein @Resource funktioniert nicht, auch mit Angabe von type = ArticleDAO.class nicht). Kann jetzt natürlich gut sein, dass in der erzeugten ArticleDAO Instanz deswegen das @Resource annotierte Feld null ist, analog zu Spring eben.
Ich versteh einfach grundsätzlich überhaupt nicht, was ich tun muss, damit Klassen injizierbar sind und selber Felder mit injizierten Klassen haben können. Googeln hat mich nur noch mehr verwirrt, um ehrlich zu sein.
 

Mercious

Mitglied
Java:
@WebServlet("")
public class HomePageController extends HttpServlet{
    private final String VIEW_NAME = "HomePage.jsp";

    @Resource (type = ArticleService.class, name = "articleService")
    private ArticleService articleService;

}

Das ist das Servlet. Keine Ahnung was hier als Wert an die Annotation übergeben werden muss, mittlerweile rate ich einfach und versuche all möglichen Kombinationen. Davon funktioniert nichts.


Java:
@Stateless (name = "articleService")
public class ArticleService {
    final int maxTeaserNameLength = 40;

    @Resource (type = ArticleDAO.class, name = "articleDAO")
    private ArticleDAO articleDAO;

    // diverse Methoden
}

Das ist der Service, der vom Controller verwendet wird. Der wird beim Hochfahren des Servers nicht gefunden, es fliegt eine NamingException.

Java:
@Stateless (name = "articleDAO")
public class ArticleDAO extends AbstractBaseDAO {
    @Resource(lookup = "jdbc/MyDB")
    private DataSource dataSource;
}

Und das DAO. Hier funktioniert das Injecten über @Resource auch nicht.

Also ich versteh wirklich Bahnhof, je mehr ich zu dem Thema google desto weniger verstehe ich. Ich weiß nicht, was ich wo konfigurieren soll, ich weiß nicht was mit was annotiert sein soll, ich weiß nicht ob Resource überhaupt so funktionieren soll, ich weiß nicht wo wie was. Ich hab wirklich noch nie zu etwas so viel recherchiert und so wenig verstanden.
 

Mercious

Mitglied
Also, ich habe es jetzt mittlerweile hinbekommen, indem ich die Annotation (@Inject) von CDI verwende. Dazu musste ich in meinem IntelliJ Projekt in den Settings noch explizit angeben, dass ich das CDI-"Modul" von glassfish verwenden möchte. Daher kamen dann die entsprechenden JARs zu meinen dependencies.

Jetzt muss ich mich noch mal über die verschiedenen Scopes kundig machen (RequestScoped, ApplicationScoped, SessionScoped, ... ). Momentan sind Service und DAO noch mit @Stateless annotiert, das ist aber eigentlich eine EJB-Annotation und keine aus dem CDI-package. Ob das schlecht ist, weiß ich nicht.
Theoretisch sollten Services und DAOs ja Singletons sein, nur weiß ich nicht, ob sich das Framework dann auch automatisch um das MT-Zeug kümmert oder nicht.
Sofern ich weiß geschieht das ja bei Servlets schon automatisch, da wird es wohl eine Instanz pro Thread/Request/whatever geben.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Junit und Mocks bei JDBC Daos Allgemeine Java-Themen 8
F Gibt es mittlerweile eine Alternative zu DaisyDiff Allgemeine Java-Themen 2
F Streams als Alternative für dieses Problem ? Allgemeine Java-Themen 15
Zrebna Alternative Darstellung eines Codesnippets Allgemeine Java-Themen 33
W Alternative für Threads Allgemeine Java-Themen 6
Thallius Alternative für SwingWorker Allgemeine Java-Themen 5
J Suche Alternative zu Jasper Reports Allgemeine Java-Themen 4
M Suche Alternative zu JFreeChart Allgemeine Java-Themen 11
D Konstruktor - jedes Objekt einzeln erzeugen - alternative? Allgemeine Java-Themen 8
MiMa Array umbau oder Alternative? Allgemeine Java-Themen 5
C Alternative zu NetworkX in Java Allgemeine Java-Themen 1
M Alternative zur Serialisierung.. Protobuf? Allgemeine Java-Themen 9
B Alternative zu nebenläufigen Prozessen Allgemeine Java-Themen 4
BonoBoo Alternative zum endlosen Instanzieren Allgemeine Java-Themen 2
F Platzsparende Alternative zu .txt-Dateien Allgemeine Java-Themen 12
E Gewollte Endlosschleife unterbrechen oder Alternative gesucht Allgemeine Java-Themen 2
F Alternative sun.jdbc.odbc.JdbcOdbcDriver (Access Datenbank) Allgemeine Java-Themen 2
F alternative zu "JPEGImageDecoderImpl" Allgemeine Java-Themen 2
T Timer oder Alternative? Allgemeine Java-Themen 3
G Alternative zu .properties Dateien Allgemeine Java-Themen 20
S Alternative zu SortedMap? Allgemeine Java-Themen 8
H Alternative zu Stack Allgemeine Java-Themen 3
pikay Jar2Exe Alternative? Allgemeine Java-Themen 17
E javax.comm: Suche eine open source Alternative zu rxtx Allgemeine Java-Themen 8
H Alternative if Schreibweise mit ? Allgemeine Java-Themen 10
G suche Property alternative Allgemeine Java-Themen 4
H Wie schön oder unschön ist dieser code - alternative ? Allgemeine Java-Themen 5
E Viele if Abfragen auf viele Strings --> Alternative zu if Allgemeine Java-Themen 8
G libext Alternative? Allgemeine Java-Themen 5
S Alternative zu Robot (wegen Umlauten) Allgemeine Java-Themen 13
foobar Alternative zu JavaHelp gesucht Allgemeine Java-Themen 2
I Alternative zu getClass().getResourceAsStream() ? Allgemeine Java-Themen 9
D System.setProperty alternative Allgemeine Java-Themen 4
J alternative zu rsh ? Allgemeine Java-Themen 5
K KeyListener-Alternative ohne anfängliches Delay ? Allgemeine Java-Themen 5
G Alternative zu split() Allgemeine Java-Themen 3
K Alternative zu JNI Allgemeine Java-Themen 3
P Alternative zu replaceAll (jdk < 1.4) Allgemeine Java-Themen 14
M Alternative zu Thread : stop() ? Allgemeine Java-Themen 10

Ähnliche Java Themen

Neue Themen


Oben