Best Practise Persistence Handling

DaBe1812

Bekanntes Mitglied
Ich bin gerade ein wenig am Lesen über JPA und jetzt hänge ich an ein paar Widersprüchlichkeiten und Fragen zur optimalen Nutzung.

Also zum ersten der Unterschied zwischen EntityManagerFactory und EntityManager. Ich verwende EntityMangaerFactories (für drei Datenquellen), das heißt ich muss die Persistenzeinheit nur einmal benennen und dann hole ich mir vom richtigen Factory einen EntityManager und arbeite dann mit dem. Den hole ich nicht einmal pro Klasse sondern einmal pro Methode. Soweit ich mich erinnern kann hat das ein Problem mit redundanten Servern, die auf dieselbe Datenquelle zugreifen behoben.
Da wollte ich mal Fragen, ob es mit einem solchen Konstrukt zu Problemen kommen kann.

Das zweite ist das DAO oder Repository Pattern. Die arbeiten beide immer mit Interfaces und dann mit einer Implementierung. Aber eigentlich heißt es ja, wenn es für ein Interface nur eine Implementierung gibt, dann kann man sich das Interface auch sparen. Eigentlich bin ich gerade bei den Persistenz-Klassen am Aufräumen, ich wollte nicht die Anzahl verdoppeln, um ein zusätzliches Interface zu haben, was am Ende einfach nur eine Ansammlung von Methodennamen ist und jedes Mal, wenn ich eine neue Methode brauche, dann muss ich das in zwei Klassen manchen, da fehlt mir irgendwie der objektive Vorteil, aber ich lass mich gerne belehren.

Bin gespannt auf eure Gedanken dazu. Aktuell kommt es mir so vor, als wenn ich mit jedem weiteren Artikel, den ich lese weniger weiß, was ich tue.
 

Oneixee5

Top Contributor
Zu EntityManagerFactory - die direkte Verwendung einer EntityManagerFactory benötigst du nur, wenn deine Software außerhalb eines Server-Context läuft. Innerhalb von von JEE, JakartaEE, Spring, ... injectest du deine Repositories. Also verwendest du auch in den seltensten Fällen einen EntityManager. Wenn ich einen EntityManager brauche, dann denke ich erst mal darüber nach - warum? Normalerweise ist das dann ein Zeichen dafür, dass ich mein Projekt besser strukturieren muss.

Im einfachsten Fall sind Repositories einfache Interfaces, eine Implementierung ist nicht erforderlich, dass erfolgt im Hintergrund automatisch durch die Persistenzframeworks, z.B. Hibernate. Manchmal sind Repositories auch Klassen, z.B. für irgendwelche Spezialfälle, Lobs, XML- oder JSON-Verarbeitung in der DB, Repositories für DB-Prozeduren, ...
Auch beide Fälle sind möglich also Interfaces + Implementierungen. Das verwende ich z.B. wenn ich mit 2 DB's/Schemen arbeite und für beide das gleiche Repository-Interface verwenden möchte.

Nochmal etwas außerhalb der Frage - wir verwenden JPA schon sehr lange und haben oft mit verschiedenen Problemen damit gekämpft. Das sind z.B. hoher Speicherverbrauch, miserable Geschwindigkeit, Fehleranfälligkeit, große Probleme bei Änderungen, uva.
Daher haben wir für uns beschlossen JPA überhaupt nicht mehr einzusetzen. Dazu gibt es verschiedene Alternativen, den pures JDBC will ja auch keiner. Ich habe ein Projekt unter Verwendung von Spring Data begonnen, größtenteils Spring Data JDBC. Ich muss sagen, ich bin begeistert. Die Geschwindigkeit ist fantastisch. Anfangs wundert man sich sich etwas über den geringen Funktionsumfang, das ist aber nur scheinbar ein Nachteil. Man gleicht das mit sehr wenig Aufwand aus, alles ist viel übersichtlicher und verständlicher und ohne Seiteneffekte.
 

DaBe1812

Bekanntes Mitglied
Innerhalb von von JEE, JakartaEE, Spring, ... injectest du deine Repositories. Also verwendest du auch in den seltensten Fällen einen EntityManager.
Wir verwenden JakartaEE und jetzt bin ich total verwirrt. Evtl. ist es wieder eine Sprachbarriere, weil ich wieder Worte falsch assoziiere?

Also ich habe eine Entity: annotiert mit @Entity, Java Repräsentation einer Datenbanktabelle. Besitzt eigentlich nur getter und setter und so ein paar Spezialfälle von denen.
Und dann habe ich das Repository. Annotiert meistens mit @ApplicationScoped, weil ich es auch direkt im Server ohne View oder Request Context brauche. Da drin dann einzelne Methoden, die Daten holen oder wegschreiben. Und da drin habe ich aktuell den EntityManager:
Java:
/*
* Frei runtergeschrieben, hab gerade keine Maschine an
*/
@ApplicationScope
public class UserRepository {
    @Inject
    private EntityManagerFactoryErsteDatenquelle emf;
    
    public void persistUser(User user) {
        EntityManager em = emf.getEntityManager();
        em.persist(user);
    }
    
    public void persistUsers(List<User> users) {
        Entitymanager em = emf.geEntityManager();
        users.forEach(em::persist);
    }
    
    public List<User> getByLastName(String lastname) {
        Entitymanager em = emf.geEntityManager();
        Query<User> query = em.createNamedQuery("User.getByLastName", User.class);
        List<User> userList = query
            .setParameter("LASTNAME", lastname)
            .getResultList();
        return userList;
    }
}
Mir fehlt hier scheinbar der Schritt zu "Man braucht keinen EntityManager". Ich arbeite halt sehr viel mit NamedQueries, weil wir im seltensten Fall direkt nach der ID suchen. Außerdem sehe ich nicht, wie der Server weiß, welche Entität aus welcher Datenquelle kommt, wenn ich nicht den richtigen EntityManager verwende.


Hibernate verwenden wir aktuell nicht, sondern Eclipselink, das wird Firmenseitig auf dem Server bereitgestellt.

Und diese JSON-Fälle haben wir auch, wo in einem Lob-Feld eben ein Konstrukt lagern.

Kein JPA verwenden? Also reines JDBC? Da weiß ich nicht mal, wie man Serverseitig bereitgestellte DB-Verbindungen verwendet? Außerdem müsste ich mich ja dann komplett selbst um die Transaktionen kümmern?
Spring zu verwenden hört sich dann schon wieder anders an. Geht das in Verbindung mit Jakarta? Bzw. lagern wir gerade die komplette Persistenzschicht in ein eigenes Modul aus, das dann dem Hauptprojekt als JAR bereitgestellt wird. Das könnte doch theoretisch ein Spring Data-Projekt sein?
 

LimDul

Top Contributor
Anstelle von der EnitymanagerFactory sollte man meines Erachtens direkt den Entitymanager injecten, siehe: https://jakarta.ee/specifications/p...persistence/jakarta/persistence/entitymanager

Insbesondere aus folgendem Punkt:
An application-managed EntityManager may be created via a call to EntityManagerFactory.createEntityManager(). The EntityManager must be explicitly closed via a call to close(), to allow resources to be cleaned up by the persistence provider. This approach places almost complete responsibility for cleanup and exception management on the client, and is thus considered quite error-prone. It is much safer to use the methods EntityManagerFactory.runInTransaction(java.util.function.Consumer<jakarta.persistence.EntityManager>) and EntityManagerFactory.callInTransaction(java.util.function.Function<jakarta.persistence.EntityManager, R>).

Deswegen direkt injecten:
In the Jakarta EE environment, a container-managed EntityManager may be obtained by dependency injection, using PersistenceContext.
 

Blender3D

Top Contributor
Aber eigentlich heißt es ja, wenn es für ein Interface nur eine Implementierung gibt, dann kann man sich das Interface auch sparen.
Das stimmt nicht so ganz. Ja bei nur einer Implementierung ist theoretisch kein Interface notwendig. Ein Interface hat aber immense Vorteile für eventuelle zukünftige Implementierungen, die dann bei Bedarf viel einfacher in ein bestehendes System übernommen werden können.
 

DaBe1812

Bekanntes Mitglied
Deswegen direkt injecten:
Okay, bisher funktioniert glücklicherweise alles, aber in dem Zuge kann ich das auch auf direktes injecten mit PersistenceContext umstellen, ist ja überschaubarer Aufwand.
Es gibt nicht nur JPA und JDBC! Du kannst dir z.B. mal Jakarta Data
Das schau ich mir morgen mal an, das hat ja einen leichten Touch von Spring.

Ein Interface hat aber immense Vorteile für eventuelle zukünftige Implementierungen,
Jupp, sehe ich so bei allen "echten" Interfaces, die ich in meiner Anwendung habe. Aber bei einem DAO-Interface sehe ich die Widerverwendbarkeit irgendwie nicht. Wenn ich in einer Entität nach Name suche, dann Suche ich nach Name und nicht in einer weiteren Implementierung nach dem Namen der Straße.
 

mrBrown

Super-Moderator
Mitarbeiter
Jupp, sehe ich so bei allen "echten" Interfaces, die ich in meiner Anwendung habe. Aber bei einem DAO-Interface sehe ich die Widerverwendbarkeit irgendwie nicht. Wenn ich in einer Entität nach Name suche, dann Suche ich nach Name und nicht in einer weiteren Implementierung nach dem Namen der Straße.
Das Was (Suche nach Name) ist ja auch bei allen Implementierungen eines Interfaces gleich (Suche nach Straße wäre also sowieso ein anderes Interface bzw eine andere Methode), das Wie unterscheidet sich zwischen den Implementierungen, eine könnte z.B. JPA nutzen und eine nur eine In-Memory-Liste, z.B. für Unit-Tests.
 

DaBe1812

Bekanntes Mitglied
Okay, das wird bei uns dann eher nicht passieren, aber wenn ich zu einer Art der Datenbeschaffung wechseln würde, dann wären ja vielleicht die Interfaces schon ausreichend, weil der Rest automatisch generiert wird.
Jetzt hatte ich mich gestern noch so schön in Jakarta Data eingelesen und fand das total super, da muss ich feststellen, dass es das erst seit diesem Jahr gibt und ich dafür in unserer Firma erstmal die Werbetrommel rühren muss, damit jemand prüft, ob wir das überhaupt verwenden dürfen.
Spring und Jakarta mischen ist nicht so der tolle Ansatz, oder? Zumindest wüsste ich nicht, wie ich in Spring Repository in Jakarta aufrufen soll, weil mir ja eigentlich die Annotation für die Verwendung des Repository fehlt.
 

mrBrown

Super-Moderator
Mitarbeiter
Jetzt hatte ich mich gestern noch so schön in Jakarta Data eingelesen und fand das total super, da muss ich feststellen, dass es das erst seit diesem Jahr gibt und ich dafür in unserer Firma erstmal die Werbetrommel rühren muss, damit jemand prüft, ob wir das überhaupt verwenden dürfen.
Was dürft ihr denn nutzen?

Jakarta Data ist doch Teil von Jakarta EE 11, wenn ihr grundsätzlich auf Jakarta EE setzt sollte ja nicht viel Werbung nötig sein.
 

DaBe1812

Bekanntes Mitglied
Werbung ist auch das falsche Wort. Hat mich jetzt fast nen Monat gekostet, bis ich unseren Nexus überhaupt verstanden habe.
Also grundsätzlich kann ich das Ding durchsuchen, wie Maven Central oder wie sie alle heißen. Und wenn ich Artefakt finde, dass ich brauche, dann kann ich das einbinden. Wenn es da ist, aber in der falschen Version, dann schreib ich das mit der Version in meine Pom, die ich gerne hätte und dann dauert der Sync minimal länger und dann steht es in unserem Nexus in der Version auch drin.
Spannend ist der Part, wie das Zeug erstmal in den Nexus aufgenommen wird, also da muss ich auf einer anderen Plattform einen Antrag schreiben und dann muss da ein Sicherheits-Typ aus unserer Abteilung benannt werden und dann wird geprüft, wie relevant das Thema für unsere Firma ist und dann wird geprüft, ob es schon ähnliche Artefakte gibt.
Hatte z.B. vorletzte Woche eine Ablehnung für die Lombok Tools in IntelliJ, weil wir Lombok zukünftig nicht mehr brauchen, weil es in Java 17 (oder war es 21?) jetzt die Repositories gibt, da ist Lombok dann überflüssig. Nur dass klar wird, auf welchem Level wir uns bewegen.
Mit derselben Begründung könnte ich also auch Jakarta Data ablehnen, es gibt ja schon Hibernate und Eclipselink im Nexus.
 

KonradN

Super-Moderator
Mitarbeiter
Mit derselben Begründung könnte ich also auch Jakarta Data ablehnen
Nein, da ist es doch genau umgedreht. Die Argumentation ist ja eben: Eine externe Abhängigkeit fliegt raus (Du hast ja geschrieben, dass ihr Lombok nicht mehr braucht - es gab also in der Vergangenheit Lombok), weil es im Standard (Hier ist Standard die Java Language Specification) etwas gibt, dass dies auch abdeckt (Was ich nicht sehe. Es geht ja nicht nur um Getter und Setter sondern auch Builder und so. Zudem haben Records - nicht Repositories - noch andere wichtige Unterschiede.)

Somit wäre hier die Begründung dann: Hibernate und Eclipselink fliegen raus, weil in dem Standard (Jetzt Jakarta EE) es eben einen Ersatz gibt. Du hast aber Angst, dass plötzlich genau umgekehrt argumentiert wird.

Das aber nur als kleiner Hinweis am Rande, weil mir die verdrehte Logik aufgefallen ist. Das ändert natürlich nichts an einer Firmenpolitik, die beliebige Argumentationen oder gar pure Willkür als Grundlage haben könnten. Generell würde ich den Antrag stellen mit eben Hinweis, dass es Bestandteil der Jakarta EE Standards ist und ja auf Basis dieses Standards entwickelt werden soll.
 

DaBe1812

Bekanntes Mitglied
Was ich nicht sehe. Es geht ja nicht nur um Getter und Setter sondern auch Builder und so. Zudem haben Records - nicht Repositories - noch andere wichtige Unterschiede
Sehen wir genauso. Die Records decken bei weitem nicht das ab, was Lombok kann. Und die Syntax finde ich auch nicht schön.

Bestandteil der Jakarta EE Standards
Ja, im weitesten Feld stimmt das. Aber das eine läuft in der GroupId jakarta.platform und das andere in jakarta.data. Den Antrag werde ich auf jeden Fall stellen.
Aber ich habe gerade mal unseren Nexus geprüft, jakartaEE ist auch nur bis 10.0 da. Jakarta Data ist ja schon 11.0. D.h. dann auch, dass es auf den Servern schon mal nicht Standardmäßig mit drauf ist, wenn es in der Firma nicht mit drin ist.
Auf der anderen Seite kann ich mich jetzt aber an andere Abteilungen wenden, die z.B. die Server bestücken, die müssen sich ja grundsätzlich so langsam auch Gedanken machen, wie sie mit dem Update auf JakartaEE 11 umgehen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Meeresgott Mongo-DB Documents größer als 16MB best practise Datenbankprogrammierung 10
Y Best Practise Facade und DAOs Datenbankprogrammierung 3
T PostgreSQL Best Practice: Konkurrierender DB-Zugriff mit meherern Programmen? Datenbankprogrammierung 20
I Hibernate - Best Practice für Lazy Loading Datenbankprogrammierung 3
R Grundlagenfrage: Best-Practice mit Nutzerdaten Datenbankprogrammierung 2
D mysql insert - performance/robustheit, "best practice" Datenbankprogrammierung 15
pkm Tomcat Classloader findet bei JPA-Persistierung die Persistence Unit nicht. Datenbankprogrammierung 11
S persistence.xml zur Laufzeit manipulieren Datenbankprogrammierung 0
F JPA persistence.xml mit EXTERNER Config Datei Datenbankprogrammierung 0
I JPA - BoneCP über die persistence.xml konfigurieren Datenbankprogrammierung 0
D Unterschiede Hibernate Vs. Java Persistence API Datenbankprogrammierung 8
J method createQuery in interface javax.persistence.EntityManager cannot be applied to given types ... Datenbankprogrammierung 2
F JPA und "persistence-unit" Datenbankprogrammierung 4
M No Persistence provider for EntityManager Datenbankprogrammierung 1
B Hibernate+JPA Exception in persistence.xml Datenbankprogrammierung 5
S Java-Persistence-API mit Hibernate Datenbankprogrammierung 3
P JPA Datenbanksettings ohne persistence.xml Datenbankprogrammierung 3
F EclipseLink persistence.xml Frage Datenbankprogrammierung 11
S JPA und Hibernate: persistence.xml: autoReconnect=true Datenbankprogrammierung 7
W EclipseLink Persistence Provider? Datenbankprogrammierung 7
G persistence.xml für MySQL - Verbindung Datenbankprogrammierung 6
A The import javax.persistence cannot be resolved Datenbankprogrammierung 1
K persistence.xml oder hibernate.cfg.xml ? Datenbankprogrammierung 10
K Was fehlt? - No Persistence provider for EntityManager Datenbankprogrammierung 4
QDog JPA persistence.xml auslagern/extern Zugriff Datenbankprogrammierung 2

Ähnliche Java Themen


Oben