Co to jest JPA? Wprowadzenie do Java Persistence API

Specyfikacją jest, że Java Persistence API jest związana z trwałością , co luźno oznacza dowolny mechanizm, dzięki któremu obiekty Java przeżywają proces aplikacji, który je utworzył. Nie wszystkie obiekty Java muszą być utrwalane, ale większość aplikacji zachowuje kluczowe obiekty biznesowe. Specyfikacja JPA pozwala zdefiniować, które obiekty powinny być utrwalane i jak te obiekty powinny być utrwalane w aplikacjach Java.

Sam w sobie JPA nie jest narzędziem ani strukturą; raczej definiuje zestaw pojęć, które mogą być implementowane przez dowolne narzędzie lub strukturę. Chociaż model mapowania obiektowo-relacyjnego (ORM) JPA był pierwotnie oparty na Hibernate, od tego czasu ewoluował. Podobnie, chociaż JPA był pierwotnie przeznaczony do użytku z relacyjnymi / SQL bazami danych, niektóre implementacje JPA zostały rozszerzone do użytku z magazynami danych NoSQL. Popularną platformą obsługującą JPA z NoSQL jest EclipseLink, implementacja referencyjna dla JPA 2.2.

WZP 2.2 w Dżakarcie EE

Java Persistence API została po raz pierwszy wydana jako podzbiór specyfikacji EJB 3.0 (JSR 220) w Java EE 5. Od tego czasu ewoluowała jako własna specyfikacja, począwszy od wydania JPA 2.0 w Java EE 6 (JSR 317). W chwili pisania tego tekstu JPA 2.2 został przyjęty jako kontynuacja jako część Dżakarty EE.

JPA i Hibernate

Ze względu na ich splecioną historię, Hibernate i JPA są często mylone. Jednak, podobnie jak specyfikacja Java Servlet, JPA zrodziło wiele kompatybilnych narzędzi i struktur; Hibernacja to tylko jedna z nich.

Opracowany przez Gavina Kinga i wydany na początku 2002 roku, Hibernate jest biblioteką ORM dla Javy. King opracował Hibernate jako alternatywę dla fasoli bytów dla wytrwałości. Ramy były tak popularne i potrzebne w tamtym czasie, że wiele z jego pomysłów zostało przyjętych i skodyfikowanych w pierwszej specyfikacji JPA.

Obecnie Hibernate ORM jest jedną z najbardziej dojrzałych implementacji JPA i nadal popularną opcją ORM w Javie. Hibernate ORM 5.3.8 (aktualna wersja w chwili pisania tego tekstu) implementuje JPA 2.2. Ponadto rodzina narzędzi Hibernate została rozszerzona o popularne narzędzia, takie jak Hibernate Search, Hibernate Validator i Hibernate OGM, które obsługują trwałość modelu domeny dla NoSQL.

JPA i EJB

Jak wspomniano wcześniej, JPA został wprowadzony jako podzbiór EJB 3.0, ale od tego czasu ewoluował jako jego własna specyfikacja. EJB to specyfikacja o innym znaczeniu niż JPA i jest zaimplementowana w kontenerze EJB. Każdy kontener EJB zawiera warstwę trwałości, która jest zdefiniowana w specyfikacji JPA.

Co to jest Java ORM?

Chociaż różnią się one wykonaniem, każda implementacja JPA zapewnia pewien rodzaj warstwy ORM. Aby zrozumieć narzędzia kompatybilne z JPA i JPA, musisz dobrze znać ORM.

Mapowanie obiektowo-relacyjne to zadanie, którego programiści mają dobry powód, aby unikać wykonywania go ręcznie. Struktura taka jak Hibernate ORM lub EclipseLink kodyfikuje to zadanie w bibliotece lub frameworku, warstwie ORM . W ramach architektury aplikacji warstwa ORM jest odpowiedzialna za zarządzanie konwersją obiektów oprogramowania do interakcji z tabelami i kolumnami w relacyjnej bazie danych. W Javie warstwa ORM konwertuje klasy i obiekty Java, dzięki czemu można je przechowywać i zarządzać nimi w relacyjnej bazie danych.

Domyślnie nazwa utrwalanego obiektu staje się nazwą tabeli, a pola stają się kolumnami. Po skonfigurowaniu tabeli każdy wiersz tabeli odpowiada obiektowi w aplikacji. Mapowanie obiektów jest konfigurowalne, ale wartości domyślne zwykle działają dobrze.

JPA z NoSQL

Do niedawna nierelacyjne bazy danych były rzadkością. Ruch NoSQL zmienił to wszystko i teraz dla programistów Java dostępnych jest wiele różnych baz danych NoSQL. Niektóre implementacje JPA ewoluowały, aby objąć NoSQL, w tym Hibernate OGM i EclipseLink.

Rysunek 1 ilustruje rolę JPA i warstwy ORM w tworzeniu aplikacji.

JavaWorld /

Konfigurowanie warstwy Java ORM

Podczas konfigurowania nowego projektu w celu korzystania z JPA należy skonfigurować magazyn danych i dostawcę JPA. Skonfigurujesz łącznik magazynu danych, aby połączyć się z wybraną bazą danych (SQL lub NoSQL). Uwzględnisz również i skonfigurujesz dostawcę JPA , który jest strukturą, taką jak Hibernate lub EclipseLink. Chociaż możesz ręcznie skonfigurować JPA, wielu programistów decyduje się na korzystanie z gotowej obsługi Springa. Zobacz „ Instalacja i konfiguracja JPA ” poniżej, aby zobaczyć demonstrację zarówno ręcznej, jak i wiosennej instalacji i konfiguracji JPA.

Java Data Objects

Java Data Objects to ustandaryzowana struktura trwałości, różniąca się od JPA przede wszystkim obsługą logiki trwałości w obiekcie oraz długotrwałą obsługą pracy z nierelacyjnymi składnicami danych. JPA i JDO są na tyle podobne, że dostawcy JDO często obsługują również JPA. Zobacz projekt Apache JDO, aby dowiedzieć się więcej o JDO w odniesieniu do innych standardów trwałości, takich jak JPA i JDBC.

Trwałość danych w Javie

Z punktu widzenia programowania warstwa ORM jest warstwą adaptera : dostosowuje język grafów obiektowych do języka SQL i tabel relacyjnych. Warstwa ORM umożliwia programistom zorientowanym obiektowo tworzenie oprogramowania, które utrwala dane bez wychodzenia z paradygmatu zorientowanego obiektowo.

Korzystając z JPA, tworzysz mapę z magazynu danych do obiektów modelu danych aplikacji. Zamiast definiować sposób zapisywania i pobierania obiektów, definiujesz mapowanie między obiektami a bazą danych, a następnie wywołujesz JPA, aby je utrwalić. Jeśli korzystasz z relacyjnej bazy danych, większość rzeczywistego połączenia między kodem aplikacji a bazą danych będzie obsługiwana przez JDBC, interfejs API Java Database Connectivity.

Zgodnie ze specyfikacją JPA zapewnia adnotacje metadanych , których można używać do definiowania mapowania między obiektami a bazą danych. Każda implementacja JPA zapewnia własny silnik adnotacji JPA. Specyfikacja JPA zapewnia również PersistanceManagerlub EntityManager, które są kluczowymi punktami kontaktu z systemem JPA (w którym kod logiki biznesowej mówi systemowi, co zrobić z mapowanymi obiektami).

Aby uczynić to wszystko bardziej konkretnym, rozważ Listing 1, który jest prostą klasą danych do modelowania muzyka.

Listing 1. Prosta klasa danych w Javie

 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... } 

MusicianKlasa w Wykazie 1 służy do przetrzymywania danych. Może zawierać prymitywne dane, takie jak pole nazwy . Może również utrzymywać relacje z innymi klasami, takimi jak mainInstrumenti performances.

Musician„s powód dla istoty ma zawierać dane. Ten typ klasy jest czasami nazywany DTO lub obiektem transferu danych . DTO są powszechną funkcją tworzenia oprogramowania. Chociaż zawierają wiele rodzajów danych, nie zawierają żadnej logiki biznesowej. Utrwalanie obiektów danych jest wszechobecnym wyzwaniem w tworzeniu oprogramowania.

Trwałość danych dzięki JDBC

Jednym ze sposobów zapisania instancji Musicianklasy w relacyjnej bazie danych byłoby użycie biblioteki JDBC. JDBC to warstwa abstrakcji, która umożliwia aplikacji wydawanie poleceń SQL bez zastanawiania się nad podstawową implementacją bazy danych.

Listing 2 pokazuje, jak można zachować Musicianklasę za pomocą JDBC.

Listing 2. JDBC wstawiający rekord

 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 

Kod na liście 2 dość samodokumentuje. georgeHarrisonObiekt może pochodzić z dowolnego miejsca (front-end przedstawienia, obsługa zewnętrznych, etc.), i ustawił jej pola Identyfikator i nazwisko. Pola obiektu są następnie używane do dostarczania wartości insertinstrukcji SQL . ( PreparedStatementKlasa jest częścią JDBC, oferując sposób bezpiecznego stosowania wartości do zapytania SQL).

Chociaż JDBC umożliwia sterowanie, które jest dostarczane z ręczną konfiguracją, jest uciążliwe w porównaniu z JPA. Aby zmodyfikować bazę danych, należy najpierw utworzyć zapytanie SQL, które odwzorowuje obiekt Java na tabele w relacyjnej bazie danych. Następnie musisz zmodyfikować SQL za każdym razem, gdy zmieni się sygnatura obiektu. Dzięki JDBC utrzymanie SQL staje się zadaniem samym w sobie.

Trwałość danych w JPA

Rozważmy teraz Listing 3, w którym utrzymujemy Musicianklasę przy użyciu JPA.

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.

Wreszcie, Musicianmoże mieć związek jeden do jednego z Quotepodmiotem, używany do reprezentowania słynny cytat: Quote famousQuote = new Quote().

Definiowanie typów relacji

WZP ma adnotacje dla każdego z jego typów mapowania relacji. Listing 7 pokazuje, jak można opisać relację jeden do wielu między Musiciani Performances.

Listing 7. Adnotacje relacji jeden do wielu