Arten von JPA-Abfragen

1. Übersicht

In diesem Tutorial werden die verschiedenen Arten von JPA-Abfragen erläutert. Darüber hinaus konzentrieren wir uns darauf, die Unterschiede zwischen ihnen zu vergleichen und die Vor- und Nachteile jedes Einzelnen zu erweitern.

2. Setup

Definieren wir zunächst die UserEntity- Klasse, die wir für alle Beispiele in diesem Artikel verwenden:

@Table(name = "users") @Entity public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

Es gibt drei grundlegende Arten von JPA-Abfragen:

  • Abfrage , geschrieben in JPQL-Syntax (Java Persistence Query Language)
  • NativeQuery , geschrieben in einfacher SQL-Syntax
  • Kriterien-API-Abfrage , programmgesteuert über verschiedene Methoden erstellt

Lassen Sie uns sie erkunden.

3. Abfrage

Eine Abfrage ähnelt in der Syntax SQL und wird im Allgemeinen zum Ausführen von CRUD-Operationen verwendet:

public UserEntity getUserByIdWithPlainQuery(Long id) { Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); jpqlQuery.setParameter("id", id); return (UserEntity) jpqlQuery.getSingleResult(); }

Diese Abfrage ruft den übereinstimmenden Datensatz aus der Benutzertabelle ab und ordnet ihn auch dem UserEntity- Objekt zu.

Es gibt zwei zusätzliche Abfrage -Untertypen:

  • TypedQuery
  • NamedQuery

Lassen Sie uns sie in Aktion sehen.

3.1. TypedQuery

Wir müssen auf die Rückgabeerklärung in unserem vorherigen Beispiel achten . JPA kann nicht ableiten, wie der Abfrageergebnistyp aussehen wird, und als Ergebnis müssen wir umwandeln.

Aber bietet JPA einen speziellen Abfrage - Untertyp als bekannt TypedQuery. Dies wird immer dann bevorzugt, wenn wir unseren Abfrageergebnistyp im Voraus kennen. Darüber hinaus ist unser Code dadurch viel zuverlässiger und einfacher zu testen.

Sehen wir uns eine TypedQuery- Alternative im Vergleich zu unserem ersten Beispiel an:

public UserEntity getUserByIdWithTypedQuery(Long id) { TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); typedQuery.setParameter("id", id); return typedQuery.getSingleResult(); }

Auf diese Weise können wir kostenlos stärker tippen und mögliche Casting-Ausnahmen vermeiden.

3.2. NamedQuery

Während wir eine Abfrage für bestimmte Methoden dynamisch definieren können, können sie schließlich zu einer schwer zu wartenden Codebasis werden. Was wäre, wenn wir allgemeine Verwendungsabfragen an einem zentralen, leicht lesbaren Ort aufbewahren könnten?

JPAs haben uns dies auch mit einem anderen Query -Subtyp behandelt, der als NamedQuery bekannt ist.

Wir definieren NamedQuery für die Entity- Klasse selbst und bieten eine zentralisierte, schnelle und einfache Möglichkeit, die zugehörigen Abfragen von Entity zu lesen und zu finden .

Alle NamedQueries müssen einen eindeutigen Namen haben.

Mal sehen, wie wir unserer UserEntity- Klasse eine NamedQuery hinzufügen können :

@Table(name = "users") @Entity @NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

Die Annotation @NamedQuery muss in einer Annotation @NamedQueries gruppiert werden, wenn wir Java vor Version 8 verwenden. Ab Java 8 können wir die Annotation @NamedQuery einfach in unserer Entity- Klasse wiederholen .

Die Verwendung einer NamedQuery ist sehr einfach:

public UserEntity getUserByIdWithNamedQuery(Long id) { Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); namedQuery.setParameter("userId", id); return (UserEntity) namedQuery.getSingleResult(); }

4. NativeQuery

Eine NativeQuery ist einfach eine SQL-Abfrage. Diese ermöglichen es uns, die volle Leistung unserer Datenbank freizusetzen, da wir proprietäre Funktionen verwenden können, die in der JPQL-beschränkten Syntax nicht verfügbar sind.

Dies ist mit Kosten verbunden. Wir verlieren die Datenbankportabilität unserer Anwendung mit NativeQuery, weil unser JPA-Anbieter keine spezifischen Details mehr von der Datenbankimplementierung oder dem Anbieter abstrahieren kann.

Lassen Sie uns sehen, wie Sie eine NativeQuery verwenden , die dieselben Ergebnisse wie unsere vorherigen Beispiele liefert:

public UserEntity getUserByIdWithNativeQuery(Long id) { Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); nativeQuery.setParameter("userId", id); return (UserEntity) nativeQuery.getSingleResult(); }

Wir müssen immer überlegen, ob eine NativeQuery die einzige Option ist. In den meisten Fällen kann eine gute JPQL- Abfrage unsere Anforderungen erfüllen und vor allem einen Abstraktionsgrad von der tatsächlichen Datenbankimplementierung beibehalten.

Die Verwendung von NativeQuery bedeutet nicht unbedingt, dass wir uns an einen bestimmten Datenbankanbieter binden. Wenn unsere Abfragen keine proprietären SQL-Befehle verwenden und nur eine Standard-SQL-Syntax verwenden, sollte der Anbieterwechsel kein Problem sein.

5. Kriterien- API-Abfrage

Kriterien- API-Abfragen sind programmgesteuert erstellte, typsichere Abfragen - ähnlich wie JPQL-Abfragen in der Syntax:

public UserEntity getUserByIdWithCriteriaQuery(Long id) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) .where(criteriaBuilder.equal(userRoot.get("id"), id))) .getSingleResult(); return queryResult; }

Es kann entmutigend sein, Kriterien- API-Abfragen aus erster Hand zu verwenden, aber sie können eine gute Wahl sein, wenn wir dynamische Abfrageelemente hinzufügen müssen oder wenn sie mit dem JPA- Metamodell gekoppelt sind .

6. Fazit

In diesem kurzen Artikel haben wir erfahren, was JPA-Abfragen sind und wie sie verwendet werden.

JPA-Abfragen sind eine großartige Möglichkeit, unsere Geschäftslogik von unserer Datenzugriffsschicht zu abstrahieren, da wir uns auf die JPQL-Syntax verlassen können und unseren JPA-Anbieter der Wahl die Abfrageübersetzung durchführen lassen .

Der gesamte in diesem Artikel vorgestellte Code ist auf GitHub verfügbar.