Was ist JPA? Einführung in die Java Persistence API

Als Spezifikation befasst sich die Java-Persistenz-API mit der Persistenz , was lose jeden Mechanismus bedeutet, durch den Java-Objekte den Anwendungsprozess überleben, der sie erstellt hat. Nicht alle Java-Objekte müssen beibehalten werden, aber die meisten Anwendungen behalten wichtige Geschäftsobjekte bei. Mit der JPA-Spezifikation können Sie definieren, welche Objekte beibehalten werden sollen und wie diese Objekte in Ihren Java-Anwendungen beibehalten werden sollen.

JPA ist an sich kein Werkzeug oder Framework. Vielmehr definiert es eine Reihe von Konzepten, die von jedem Tool oder Framework implementiert werden können. Während das ORM-Modell (Object Relational Mapping) von JPA ursprünglich auf Hibernate basierte, hat es sich seitdem weiterentwickelt. Während JPA ursprünglich für die Verwendung mit relationalen / SQL-Datenbanken vorgesehen war, wurden einige JPA-Implementierungen für die Verwendung mit NoSQL-Datenspeichern erweitert. Ein beliebtes Framework, das JPA mit NoSQL unterstützt, ist EclipseLink, die Referenzimplementierung für JPA 2.2.

JPA 2.2 in Jakarta EE

Die Java Persistence API wurde erstmals als Teilmenge der EJB 3.0-Spezifikation (JSR 220) in Java EE 5 veröffentlicht. Seitdem hat sie sich als eigene Spezifikation entwickelt, beginnend mit der Veröffentlichung von JPA 2.0 in Java EE 6 (JSR 317). Zum jetzigen Zeitpunkt wurde JPA 2.2 als Teil von Jakarta EE zur Fortsetzung angenommen.

JPA und Ruhezustand

Aufgrund ihrer miteinander verflochtenen Geschichte sind Hibernate und JPA häufig miteinander verbunden. Wie die Java-Servlet-Spezifikation hat JPA jedoch viele kompatible Tools und Frameworks hervorgebracht. Der Ruhezustand ist nur einer von ihnen.

Hibernate wurde von Gavin King entwickelt und Anfang 2002 veröffentlicht und ist eine ORM-Bibliothek für Java. King entwickelte Hibernate als Alternative zu Entity Beans für die Persistenz. Das Framework war zu dieser Zeit so beliebt und notwendig, dass viele seiner Ideen in der ersten JPA-Spezifikation übernommen und kodifiziert wurden.

Hibernate ORM ist heute eine der ausgereiftesten JPA-Implementierungen und immer noch eine beliebte Option für ORM in Java. Hibernate ORM 5.3.8 (die aktuelle Version zum Zeitpunkt dieses Schreibens) implementiert JPA 2.2. Darüber hinaus wurde die Toolfamilie von Hibernate um beliebte Tools wie Hibernate Search, Hibernate Validator und Hibernate OGM erweitert, die die Persistenz von Domänenmodellen für NoSQL unterstützen.

JPA und EJB

Wie bereits erwähnt, wurde JPA als Teilmenge von EJB 3.0 eingeführt, hat sich jedoch seitdem als eigene Spezifikation weiterentwickelt. EJB ist eine Spezifikation mit einem anderen Fokus als JPA und wird in einem EJB-Container implementiert. Jeder EJB-Container enthält eine Persistenzschicht, die in der JPA-Spezifikation definiert ist.

Was ist Java ORM?

Während sie sich in der Ausführung unterscheiden, bietet jede JPA-Implementierung eine Art ORM-Schicht. Um JPA- und JPA-kompatible Tools zu verstehen, müssen Sie ORM gut verstehen.

Die objektrelationale Zuordnung ist eine Aufgabe , die Entwickler aus gutem Grund vermeiden sollten. Ein Framework wie Hibernate ORM oder EclipseLink codiert diese Aufgabe in eine Bibliothek oder ein Framework, eine ORM-Schicht . Als Teil der Anwendungsarchitektur ist die ORM-Schicht für die Verwaltung der Konvertierung von Softwareobjekten zur Interaktion mit den Tabellen und Spalten in einer relationalen Datenbank verantwortlich. In Java konvertiert die ORM-Schicht Java-Klassen und -Objekte, sodass sie in einer relationalen Datenbank gespeichert und verwaltet werden können.

Standardmäßig wird der Name des Objekts, das beibehalten wird, zum Namen der Tabelle, und Felder werden zu Spalten. Sobald die Tabelle eingerichtet ist, entspricht jede Tabellenzeile einem Objekt in der Anwendung. Die Objektzuordnung ist konfigurierbar, aber die Standardeinstellungen funktionieren in der Regel gut.

JPA mit NoSQL

Bis vor kurzem waren nicht relationale Datenbanken ungewöhnliche Kuriositäten. Die NoSQL-Bewegung hat all das geändert, und jetzt stehen Java-Entwicklern eine Vielzahl von NoSQL-Datenbanken zur Verfügung. Einige JPA-Implementierungen wurden entwickelt, um NoSQL zu unterstützen, einschließlich Hibernate OGM und EclipseLink.

Abbildung 1 zeigt die Rolle von JPA und der ORM-Schicht bei der Anwendungsentwicklung.

JavaWorld /

Konfigurieren der Java ORM-Schicht

Wenn Sie ein neues Projekt für die Verwendung von JPA einrichten, müssen Sie den Datenspeicher und den JPA-Anbieter konfigurieren. Sie konfigurieren einen Datenspeicher-Connector für die Verbindung mit der von Ihnen ausgewählten Datenbank (SQL oder NoSQL). Sie werden auch den JPA-Anbieter einschließen und konfigurieren , bei dem es sich um ein Framework wie Hibernate oder EclipseLink handelt. Während Sie JPA manuell konfigurieren können, verwenden viele Entwickler die sofort einsatzbereite Unterstützung von Spring. Unter " Installation und Einrichtung von JPA " finden Sie eine Demonstration der manuellen und Spring-basierten Installation und Einrichtung von JPA.

Java-Datenobjekte

Java Data Objects ist ein standardisiertes Persistenz-Framework, das sich von JPA hauptsächlich durch die Unterstützung der Persistenzlogik im Objekt und durch seine langjährige Unterstützung für die Arbeit mit nicht relationalen Datenspeichern unterscheidet. JPA und JDO sind so ähnlich, dass JDO-Anbieter häufig auch JPA unterstützen. Weitere Informationen zu JDO in Bezug auf andere Persistenzstandards wie JPA und JDBC finden Sie im Apache JDO-Projekt.

Datenpersistenz in Java

Aus Programmiersicht ist die ORM-Schicht eine Adapterschicht : Sie passt die Sprache von Objektgraphen an die Sprache von SQL und relationalen Tabellen an. Die ORM-Schicht ermöglicht es objektorientierten Entwicklern, Software zu erstellen, die Daten beibehält, ohne jemals das objektorientierte Paradigma zu verlassen.

Wenn Sie JPA verwenden, erstellen Sie eine Zuordnung vom Datenspeicher zu den Datenmodellobjekten Ihrer Anwendung. Anstatt zu definieren, wie Objekte gespeichert und abgerufen werden, definieren Sie die Zuordnung zwischen Objekten und Ihrer Datenbank und rufen dann JPA auf, um sie beizubehalten. Wenn Sie eine relationale Datenbank verwenden, wird ein Großteil der tatsächlichen Verbindung zwischen Ihrem Anwendungscode und der Datenbank von JDBC, der Java Database Connectivity API, verwaltet.

Als Spezifikation stellt JPA Metadatenanmerkungen bereit , mit denen Sie die Zuordnung zwischen Objekten und der Datenbank definieren. Jede JPA-Implementierung bietet eine eigene Engine für JPA-Annotationen. Die JPA-Spezifikation enthält auch die PersistanceManageroder EntityManager, die die wichtigsten Kontaktpunkte mit dem JPA-System sind (wobei Ihr Geschäftslogikcode dem System mitteilt, was mit den zugeordneten Objekten zu tun ist).

Um dies alles konkreter zu machen, betrachten Sie Listing 1, eine einfache Datenklasse zum Modellieren eines Musikers.

Listing 1. Eine einfache Datenklasse in Java

 public class Musician { private Long id; private String name; private Instrument mainInstrument; private ArrayList performances = new ArrayList(); public Musician( Long id, String name){ /* constructor setters... */ } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setMainInstrument(Instrument instr){ this.instrument = instr; } public Instrument getMainInstrument(){ return this.instrument; } // ...Other getters and setters... } 

Die MusicianKlasse in Listing 1 wird zum Speichern von Daten verwendet. Es kann primitive Daten wie die enthalten Name Feld. Es kann auch Beziehungen zu anderen Klassen wie mainInstrumentund enthalten performances.

MusicianDer Grund zu sein ist, Daten zu enthalten. Diese Art von Klasse wird manchmal als DTO oder Datenübertragungsobjekt bezeichnet . DTOs sind ein gemeinsames Merkmal der Softwareentwicklung. Obwohl sie viele Arten von Daten enthalten, enthalten sie keine Geschäftslogik. Das Fortbestehen von Datenobjekten ist eine allgegenwärtige Herausforderung in der Softwareentwicklung.

Datenpersistenz mit JDBC

Eine Möglichkeit, eine Instanz der MusicianKlasse in einer relationalen Datenbank zu speichern, besteht in der Verwendung der JDBC-Bibliothek. JDBC ist eine Abstraktionsebene, mit der eine Anwendung SQL-Befehle ausgeben kann, ohne über die zugrunde liegende Datenbankimplementierung nachzudenken.

Listing 2 zeigt, wie Sie die MusicianKlasse mit JDBC beibehalten können.

Listing 2. JDBC fügt einen Datensatz ein

 Musician georgeHarrison = new Musician(0, "George Harrison"); String myDriver = "org.gjt.mm.mysql.Driver"; String myUrl = "jdbc:mysql://localhost/test"; Class.forName(myDriver); Connection conn = DriverManager.getConnection(myUrl, "root", ""); String query = " insert into users (id, name) values (?, ?)"; PreparedStatement preparedStmt = conn.prepareStatement(query); preparedStmt.setInt (1, 0); preparedStmt.setString (2, "George Harrison"); preparedStmt.setString (2, "Rubble"); preparedStmt.execute(); conn.close(); // Error handling removed for brevity 

Der Code in Listing 2 ist ziemlich selbstdokumentierend. Das georgeHarrisonObjekt kann von überall her kommen (Front-End-Übermittlung, externer Dienst usw.) und seine ID- und Namensfelder sind festgelegt. Die Felder im Objekt werden dann verwendet, um die Werte einer SQL- insertAnweisung anzugeben . (Die PreparedStatementKlasse ist Teil von JDBC und bietet eine Möglichkeit, Werte sicher auf eine SQL-Abfrage anzuwenden.)

JDBC ermöglicht zwar die Steuerung, die mit der manuellen Konfiguration geliefert wird, ist jedoch im Vergleich zu JPA umständlich. Um die Datenbank zu ändern, müssen Sie zunächst eine SQL-Abfrage erstellen, die von Ihrem Java-Objekt den Tabellen in einer relationalen Datenbank zugeordnet wird. Sie müssen dann die SQL ändern, wenn sich eine Objektsignatur ändert. Mit JDBC wird das Verwalten von SQL zu einer Aufgabe für sich.

Datenpersistenz mit JPA

Betrachten Sie nun Listing 3, in dem wir die MusicianKlasse mit JPA beibehalten.

Listing 3. Persisting George Harrison with JPA

 Musician georgeHarrison = new Musician(0, "George Harrison"); musicianManager.save(georgeHarrison); 

Listing 3 replaces the manual SQL from Listing 2 with a single line, session.save(), which instructs JPA to persist the object. From then on, the SQL conversion is handled by the framework, so you never have to leave the object-oriented paradigm.

Metadata annotations in JPA

The magic in Listing 3 is the result of a configuration, which is created using JPA's annotations. Developers use annotations to inform JPA which objects should be persisted, and how they should be persisted.

Listing 4 shows the Musician class with a single JPA annotation.

Listing 4. JPA's @Entity annotation

 @Entity public class Musician { // ..class body } 

Persistent objects are sometimes called entities. Attaching @Entity to a class like Musician informs JPA that this class and its objects should be persisted.

XML vs. annotation-based configuration

JPA also supports using external XML files, instead of annotations, to define class metadata. But why would you do that to yourself?

Configuring JPA

Like most modern frameworks, JPA embraces coding by convention (also known as convention over configuration), in which the framework provides a default configuration based on industry best practices. As one example, a class named Musician would be mapped by default to a database table called Musician.

The conventional configuration is a timesaver, and in many cases it works well enough. It is also possible to customize your JPA configuration. As an example, you could use JPA's @Table annotation to specify the table where the Musician class should be stored.

Listing 5. JPA's @Table annotation

 @Entity @Table(name="musician") public class Musician { // ..class body } 

Listing 5 tells JPA to persist the entity (Musician class) to the musician table.

Primary key

In JPA, the primary key is the field used to uniquely identify each object in the database. The primary key is useful for referencing and relating objects to other entities. Whenever you store an object in a table, you will also specify the field to use as its primary key.

In Listing 6, we tell JPA what field to use as Musician's primary key.

Listing 6. Specifying the primary key

 @Entity public class Musician { @Id private Long id; 

In this case, we've used JPA's @Id annotation to specify the id field as Musician's primary key. By default, this configuration assumes the primary key will be set by the database--for instance, when the field is set to auto-increment on the table.

JPA supports other strategies for generating an object's primary key. It also has annotations for changing individual field names. In general, JPA is flexible enough to adapt to any persistence mapping you might need.

CRUD operations

Once you've mapped a class to a database table and established its primary key, you have everything you need to create, retrieve, delete, and update that class in the database. Calling session.save() will create or update the specified class, depending on whether the primary-key field is null or applies to en existing entity. Calling entityManager.remove() will delete the specified class.

Entity relationships in JPA

Simply persisting an object with a primitive field is only half the equation. JPA also has the capability to manage entities in relation to one another. Four kinds of entity relationships are possible in both tables and objects:

    1. One-to-many
    2. Many-to-one
    3. Many-to-many
    4. One-to-one

Each type of relationship describes how an entity relates to other entities. For example, the Musician entity could have a one-to-many relationship with Performance, an entity represented by a collection such as List or Set.

If the Musician included a Band field, the relationship between these entities could be many-to-one, implying collection of Musicians on the single Band class. (Assuming each musician only performs in a single band.)

If Musician included a BandMates field, that could represent a many-to-many relationship with other Musician entities.

Schließlich Musiciankönnte eine Eins-zu-Eins-Beziehung zu einer QuoteEntität bestehen, die verwendet wird, um ein berühmtes Zitat darzustellen : Quote famousQuote = new Quote().

Beziehungstypen definieren

JPA verfügt über Anmerkungen für jeden seiner Beziehungszuordnungstypen. Listing 7 zeigt, wie Sie die Eins-zu-Viele-Beziehung zwischen Musicianund Performances mit Anmerkungen versehen können .

Listing 7. Annotieren einer Eins-zu-Viele-Beziehung