20 Punkte von carnoxen 2024-12-05 | 22 Kommentare | Auf WhatsApp teilen

Zusammenfassung

JPA/Hibernate ist zu einem weit verbreiteten Framework geworden, weil man damit in Java-Code angeblich kein SQL mehr schreiben muss. Ich möchte jedoch dafür plädieren, es in neuen Projekten nicht zu verwenden.

Gründe

Extrem lange offizielle Dokumentation

Die offizielle Dokumentation umfasst als PDF ganze 406 Seiten und ist damit länger als Der Herr der Ringe (231 Seiten) und das SQL-Standarddokument (288 Seiten). Man braucht kein Masterstudium, um Datenbankabfragen zu lernen.

Veränderlichkeit

  1. Selbst wenn eine Entity bestimmte Elemente zwingend benötigt, wird ein parameterloser Konstruktor erzwungen.
  2. Man kann Vererbung nicht verhindern, indem man in Entity-Klassen die Schlüsselwörter final oder abstract verwendet.
  3. Reflection/Introspection missachtet das OOP-Prinzip der Kapselung.
  4. Jemand kann bösartigen Code einschleusen und die Daten vollständig vernichten.

Lazy Loading und Cache

  1. Die Annotation @Lazy ist für Anfänger eine der schlimmsten Techniken überhaupt. Dennoch lässt sie sich kaum vermeiden, wenn das Domain-Design nicht zu Hibernate passt oder man keine Queries schreiben kann.
  2. Der Cache-Mechanismus ist schwer zu verstehen. Und selbst wenn man ihn versteht, muss man nicht Query-Ergebnisse, sondern die Entities selbst im Cache speichern.

Speicher-Datenbank-Synchronisierung (Flush)

Die Technik Flush synchronisiert im Speicher abgelegte Objekte mit der Datenbank. Das verursacht zwei Probleme.

  • Sobald Flush greift, sind Änderungen im Speicher faktisch abgeschlossen, sodass andere Persistenzwerkzeuge als Hibernate praktisch ausgeschlossen sind, und
  • wenn während des Flush Konflikte auftreten, können Stack-Trace-Fehler entstehen, die nichts mit dem eigentlichen Code zu tun haben.

Nur bestimmte Spalten einer Tabelle abrufen

Wenn man bei einer Entity nur auf eine einzelne Spalte zugreifen will, ist der SQL-Ansatz simpel:

select url from image   
where id = 'F462E8D9-9DF7-4A58-9112-EDE0434B4ACE';  

Hibernate lädt jedoch grundsätzlich alle Spalten der Entity. Um das zu vermeiden, ist ein komplizierter Umweg nötig.

Constraints für Spalten definieren

Um Constraints für eine bestimmte Spalte zu definieren, muss man mehrere Annotationen wie unten anbringen.

...  
    @NotNull  
    @NotEmpty  
    @Email  
    private String email;  
...  

Diese Methode bringt folgende Probleme mit sich.

  • Für diese Bedingungen lassen sich keine Unit-Tests schreiben.
  • Während eines Flush-Vorgangs ist es zu spät, diesen Verarbeitungsablauf noch nachvollziehen zu wollen.
  • Die möglichen Exceptions sind allgemein und nutzlos.
  • Geschäftsregeln werden nur als technische Regeln behandelt.

Probleme auf strategischer Ebene

  1. Framework-Updates sind schlimm, Abwärtskompatibilität wird ignoriert, und man wird zwangsläufig abhängig. Die Unternehmen dahinter gewöhnen sich daran, dass es selbstverständlich sei, ihr eigenes Framework zur Monopolisierung einzusetzen. Diesen Teufelskreis muss man stoppen.
  2. Einen Proof of Concept unbedingt nur über ein Framework gewinnen zu wollen, verengt lediglich den eigenen Blick — und bei JPA/Hibernate ganz besonders. Man sollte nicht das Geringste davon tolerieren.

Was sollte man tun?

Verwendet SQL

Mit SQL ist alles möglich. Jeder Programmierer kennt es, Queries sind intuitiv, und man braucht kein Framework.

Mein Vorgesetzter will aber Hibernate einsetzen

Kündigt oder arbeitet daran, den Code vom Framework zu entkoppeln.

Wenn ihr es bereits verwendet ...

  1. Macht den Sichtbarkeitsgrad des Standardkonstruktors und der Setter nicht zu public.
  2. Verwendet statt von SQL generierter IDs Zeichenketten wie UUIDs.
  3. Verwendet statt des Namens XXXRepository lieber XXXDao.
  4. Verwendet die Annotation @SequenceGenerator nicht.
  5. Trennt Domain-Klassen und DAO-Klassen über interface.
  6. Verwendet keine Eins-zu-viele-Beziehungen (@OneToMany usw.) und vermeidet nach Möglichkeit lieber Entity-Mapping.

Fazit

JPA/Hibernate: weg damit.

  • Es gibt kürzere und bessere Dokumentation zur Lösung von Geschäftsproblemen.
  • Haltet nicht zu starr an einem zu schnellen Designansatz fest.
  • Zeigt dem nächsten Entwickler, der euren Code pflegen muss, etwas Großzügigkeit.

Was verwendet ihr?

  1. JPA/Hibernate
  2. Andere ORM-Techniken

22 Kommentare

 
askaskm 2024-12-16

Ich bin gegen die Meinung, JPA/Hibernate aufzugeben.

„Sehr lange offizielle Dokumentation“
Auch SQL ist schwer, wenn man es zum ersten Mal lernt. Ist es denn einfach, komplexe Joins, Subqueries, Stored Procedures und Funktionen vollständig zu verstehen?
Bei JPA reicht es völlig aus, anfangs nur die Kernkonzepte zu verstehen. Tiefergehende Inhalte kann man nachschlagen, wenn sie gebraucht werden.
Und es gibt LLMs.

„Probleme mit Mutabilität und Reflection“
Das ist eine Sorge, die daraus entsteht, dass man die Funktionsweise des Frameworks nicht versteht.
In der Praxis treten dadurch kaum jemals echte Probleme auf.
Im Gegenteil: Durch Reflection wird das Object Mapping automatisiert, was die Produktivität deutlich steigert.

„Lazy Loading und Cache“
@Lazy ist also „die schlimmste Technik“? Es ist eine sehr nützliche Funktion, um das N+1-Problem zu lösen und die Performance zu optimieren.
Der Cache-Mechanismus hilft im Gegenteil erheblich bei der Verbesserung der Performance.

„Nur bestimmte Spalten einer Tabelle abrufen“
Mit JPQL oder Projection lassen sich die benötigten Spalten leicht gezielt abfragen.
Und man kann es zusammen mit QueryDSL verwenden.

Ich denke, das Ziel von ORM ist nicht, SQL vollständig zu ersetzen, sondern Entwicklern dabei zu helfen, sich stärker auf die Business-Logik zu konzentrieren..

 
bbulbum 2024-12-09

Ich bin zwar ein ORM-Skeptiker, aber ich glaube nicht, dass hier ausreichend Alternativen aufgezeigt wurden.

Wenn man zu stark auf ORM setzt, ist das wirklich ein Fass ohne Boden, und wie oben erwähnt, kann es passieren, dass man sich in einer noch größeren Dokumentationslandschaft als der SQL-Dokumentation abmüht und daran zugrunde geht.

Ich entwickle derzeit in einem privaten Projekt ohne ORM, aber sobald ich anfange, ein Design mit Blick auf Wiederverwendbarkeit zu entwerfen, gerate ich manchmal in eine Richtung, bei der ich denke: Eigentlich baue ich gerade einfach selbst ein ORM. haha

 
ilbanin00 2024-12-07

Dadurch, dass man ein Framework verwendet, kann man mit anderen Entwicklern, die dasselbe Framework im professionellen Umfeld einsetzen, ein gemeinsames Paradigma teilen — dieser Punkt scheint in solchen Artikeln, die immer dazu raten, so etwas nicht zu verwenden, stets ignoriert zu werden.

 
dothx 2024-12-06

Wenn es viele Tabellen und viele Spalten gibt (zum Beispiel 50 Tabellen und mehr als 100 Spalten pro Tabelle), wird die Hölle losbrechen, wenn man einfach pures SQL verwendet.

Ich denke allerdings, dass es eine enorme Verschwendung ist, für kleine Services JPA/Hibernate einzusetzen.

Wie immer scheint so eine Meinung vom jeweiligen Fall abzuhängen.

(Das hier als Beispiel Genannte hat ja auch nur 3–4 Spalten ...)

 
jpumpkin94 2024-12-06

Ich denke, die letzte Frage im obigen Beitrag sollte etwas angepasst werden.

Im Java-Umfeld könnte man es als 1. ORM vs. 2. Nicht-ORM zusammenfassen.

  1. Bei ORM wird de facto praktisch nur die Kombination aus JPA/Hibernate verwendet.
  2. Dazu gehören etwa MyBatis, JOOQ und SpringDataJDBC. Dabei wird in der Regel SQL direkt gehandhabt.

Sowohl 1 als auch 2 haben klare Vor- und Nachteile, daher ist es nicht angemessen, wie im obigen Beitrag zu einem so extremen Schluss zu kommen.

Bei uns ist es zum Beispiel so:
Wir verwenden mit JPA/Hibernate/QueryDSL ein ORM und gleichzeitig auch MyBatis.

Wir nutzen ORM, um die Produktivität so weit wie möglich zu steigern,
und für Queries, die sich mit ORM nur schwer abdecken lassen, verwenden wir MyBatis.

Und egal, ob man sich oben für 1 oder 2 entscheidet: Man sollte SQL gut beherrschen.

 
carnoxen 2024-12-06

Ich würde es auch gern bearbeiten, aber die Website bietet keine solche Funktion ...

 
kallare 2024-12-06

Ich glaube, hier wird so getan, als wüsste man gar nicht mehr, warum ORM überhaupt populär geworden ist.

Zwar gibt es gewisse Lernkosten, aber sobald man sich daran gewöhnt hat, steigt die Produktivität eindeutig.

SQL wirkt zwar einfach, aber diese Ermüdung, wenn man jedes einzelne SQL-Statement von Hand schreibt ... Und wenn sich dann Tabellen ändern, muss man auch alle betroffenen Queries einzeln anpassen, sodass die Wartung von SQL alles andere als trivial ist. Gerade weil es klein und einfach ist, steigt der Arbeitsaufwand stark an (deshalb kommt ja auch ständig das Thema Produktivität auf).

Außerdem treten Fehler in SQL erst zur Laufzeit auf und sind deshalb schwer zu finden. Wenn man dann auch noch Schutz gegen Angriffe wie SQL-Injection Stück für Stück selbst einbaut, landet man am Ende doch wieder bei zusätzlichem Code zur Query-Erzeugung (meistens fängt es mit einer einfachen Template-Form an ...). Wenn man das weiterführt, kommt am Ende wieder etwas ORM-Ähnliches heraus — warum dann nicht einfach gleich ORM verwenden?

Das erinnert mich an den Beitrag, der vor ein paar Tagen gepostet wurde.
https://de.news.hada.io/topic?id=17955

 
laracool 2024-12-06

Ich stimme zu.
Ich habe oft den Eindruck, dass die Gründe für den Einsatz von ORM und seine Vorteile nicht vollständig verstanden werden.

Außerdem scheint es nicht viele Menschen zu geben, die versuchen, das über ORM tatsächlich ausgeführte SQL zu analysieren oder zu verstehen.
Es wäre gut, wenn stärker bekannt würde, dass es nicht nur über reine Bequemlichkeit hinausgeht, sondern auch dabei helfen kann, SQL-Optimierung und die Funktionsweise der Datenbank tiefgehend zu verstehen.

 
jamsya 2024-12-06

Ich finde, man muss sich nicht auf eines der beiden Extreme versteifen – dass man es unbedingt nutzen muss oder auf keinen Fall nutzen darf, haha;;
Wenn ich Produktivität brauche, nutze ich ein ORM,
und komplexe Queries, die sich mit ORM nicht abdecken lassen, oder Queries, die stärker optimiert werden müssen, behandle ich mit Raw Queries.
Ich denke, ob ORM oder Raw Query, sollte man je nach Situation passend danach auswählen, was man wie bauen will.

 
xhfleodhkd 2024-12-06

Im Allgemeinen kann ich mir vorstellen, dass das bei Daten funktioniert, deren DB-Normalisierung gut umgesetzt ist und bei denen keine großen Joins nötig sind.
Wenn man jedoch nicht alles – angefangen bei der DB-Normalisierung – sauber über einen DBA verwalten kann, kann auch ein ORM eine gute Wahl sein. Gerade die Vorteile, die entstehen, wenn man Daten auf der abrufenden Seite per Relationship statt per Join holt, sind meiner Meinung nach ein gutes Beispiel dafür, warum man überhaupt ORM verwendet.
Natürlich stimme ich der Ansicht zu, dass Frameworks das Wachstum von Entwicklern einschränken können und dass man die Abhängigkeit von Frameworks senken sollte,
aber der Meinung, man solle ORM grundsätzlich nicht verwenden, kann ich mich nicht ohne Weiteres anschließen.
Es wirkt auf mich so, als würde dabei vorausgesetzt, dass alle Unternehmen einen DBA haben und mit soliden Methoden wie DDD oder TDD entwickeln.
Wenn das in der Praxis tatsächlich so umgesetzt würde, kann ich mir gar nicht vorstellen, wie viel chaotischer der Code am Ende noch werden könnte.

 
aer0700 2024-12-06

Wenn ich ein Backend mit PYTHON baue, nutze ich eigentlich jedes Mal so etwas wie SQLALCHEMY oder DJANGO ORM.
Ob man SQL direkt schreibt oder ein ORM verwendet – sobald man sich daran gewöhnt hat, fühlt es sich für mich nicht nach einem großen Unterschied an, daher habe ich mir darüber nie groß Gedanken gemacht. Es gibt aber offenbar auch die Meinung, dass man ORM besser nicht verwenden sollte.
Der Ansicht, die Abhängigkeit vom Framework zu verringern, stimme ich zu. Man sollte nicht nur mit DJANGO ORM umgehen können und dann SQL selbst nicht beherrschen...

 
beoks 2024-12-06

Hm, na ja, ich bin anderer Meinung. Ich betreibe derzeit einen Service mit etwa 3.000 Tabellen, und weil die Domain so komplex ist, habe ich für eine einzelne Query grundsätzlich oft schon mehrere Dutzend Zeilen geschrieben. Wenn man dann noch dynamische Queries bedenkt, wird es wirklich unerquicklich. Wegen der Komplexität sind auch viele Bugs entstanden, und die Wartung war schwierig. Ich denke, dass in komplexen Domains ein ORM eher im Vorteil ist.

 
xhfleodhkd 2024-12-06

In meinem Fall habe ich Erfahrung mit der Wartung einer nicht normalisierten Datenbank.
Damals habe ich dynamische Abfragen ohne ORM mit normalem SQL geschrieben,
und dadurch gab es Fälle, in denen der Code schwerer verständlich wurde.
Ich denke, dass es nicht nur bei komplexen Domains, sondern auch bei Domains mit unzureichender Normalisierung durchaus Raum für den Einsatz gibt.

 
carnoxen 2024-12-06

Oh, dann muss man das wohl nicht negativ sehen.

 
tsboard 2024-12-06

Ich persönlich würde auch einfach empfehlen, direkt SQL zu verwenden. In der JS-Welt werden zwar oft Tools wie Prisma genutzt, aber SQL ist nun wirklich keine so schwierige Sprache, und ich finde es etwas abschreckend, dass für Datenbank-I/O so viel unnötige Abstraktion verlangt wird.

 
znjadong 2024-12-06

Vielleicht liegt es auch daran, dass es gerade im js/ts-Bereich auffallend viele ORMs gibt, die einfach unausgereift sind.

 
carnoxen 2024-12-06

Dann reicht wohl so etwas wie JDBC, oder? Ich muss gerade daran denken, dass jemand, mit dem ich früher zusammengearbeitet habe, sagte: „JPA ist langsam, also nimm lieber etwas anderes.“

 
roxie 2024-12-06

Klingt wie eine Legende.

 
caniel 2024-12-06

Es wirkt fast so, als wäre es ein Trend, statt auf Frameworks eher zu den Grundlagen zurückzukehren.
HTMX, SQL und so weiter..

 
carnoxen 2024-12-06

Es hat zwar den Nachteil, dass man das Rad neu erfinden muss.

 
misolab 2024-12-06

Es hat schon auch Vorteile ..
2. MyBatis (ist zwar kein ORM, haha)

 
carnoxen 2024-12-06

Ich hätte wohl besser nicht auf ein ORM, sondern auf DAO umsteigen sollen.