Vad är JPA? Introduktion till Java Persistence API

Som en specifikation handlar Java Persistence API om uthållighet , vilket löst betyder alla mekanismer genom vilka Java-objekt överlever applikationsprocessen som skapade dem. Inte alla Java-objekt behöver bestå, men de flesta program kvarstår viktiga affärsobjekt. Med JPA-specifikationen kan du definiera vilka objekt som ska bestå och hur dessa objekt ska bestå i dina Java-applikationer.

JPA är i sig inte ett verktyg eller ramverk; snarare definierar den en uppsättning begrepp som kan implementeras av vilket verktyg eller ram som helst. Medan JPA: s ORM-modell (objektsrelationell kartläggning) ursprungligen baserades på viloläge har den sedan utvecklats. Även om JPA ursprungligen var avsedd för användning med relations- / SQL-databaser, har vissa JPA-implementeringar utökats för användning med NoSQL-datalagrar. Ett populärt ramverk som stöder JPA med NoSQL är EclipseLink, referensimplementeringen för JPA 2.2.

JPA 2.2 i Jakarta EE

Java Persistence API släpptes först som en delmängd av EJB 3.0-specifikationen (JSR 220) i Java EE 5. Den har sedan dess utvecklats som sin egen specifikation, från och med lanseringen av JPA 2.0 i Java EE 6 (JSR 317). När detta skrivs har JPA 2.2 antagits för fortsättning som en del av Jakarta EE.

JPA och Hibernate

På grund av deras sammanflätade historia är Hibernate och JPA ofta sammanslagna. Liksom Java Servlet-specifikationen har JPA skapat många kompatibla verktyg och ramar; Viloläge är bara en av dem.

Hibernate är ett ORM-bibliotek för Java som utvecklats av Gavin King och släpptes i början av 2002. King utvecklade Hibernate som ett alternativ till entitetsbönor för uthållighet. Ramverket var så populärt och så nödvändigt då, att många av dess idéer antogs och kodifierades i den första JPA-specifikationen.

Idag är Hibernate ORM en av de mest mogna JPA-implementeringarna och fortfarande ett populärt alternativ för ORM i Java. Hibernate ORM 5.3.8 (den nuvarande versionen i skrivande stund) implementerar JPA 2.2. Dessutom har Hibernates familj av verktyg expanderat till att omfatta populära verktyg som Hibernate Search, Hibernate Validator och Hibernate OGM, som stöder domänmodell persistens för NoSQL.

JPA och EJB

Som tidigare nämnts introducerades JPA som en delmängd av EJB 3.0, men har sedan dess utvecklats som sin egen specifikation. EJB är en specifikation med ett annat fokus än JPA och implementeras i en EJB-container. Varje EJB-behållare innehåller ett uthållighetsskikt som definieras av JPA-specifikationen.

Vad är Java ORM?

Medan de skiljer sig åt i utförandet, erbjuder varje JPA-implementering någon form av ORM-lager. För att förstå JPA- och JPA-kompatibla verktyg måste du ha ett bra grepp om ORM.

Objektrelationell kartläggning är en uppgift som utvecklare har goda skäl att undvika att göra manuellt. Ett ramverk som Hibernate ORM eller EclipseLink kodar den uppgiften i ett bibliotek eller ramverk, ett ORM-lager . Som en del av applikationsarkitekturen ansvarar ORM-skiktet för att hantera omvandlingen av programvaruobjekt för att interagera med tabellerna och kolumnerna i en relationsdatabas. I Java konverterar ORM-lagret Java-klasser och objekt så att de kan lagras och hanteras i en relationsdatabas.

Som standard blir namnet på objektet som kvarstår namnet på tabellen och fält blir kolumner. När tabellen har ställts in motsvarar varje tabellrad ett objekt i applikationen. Objektmappning kan konfigureras, men standardinställningar tenderar att fungera bra.

JPA med NoSQL

Fram till ganska nyligen var icke-relationsdatabaser ovanliga kuriositeter. NoSQL-rörelsen förändrade allt detta, och nu finns en mängd olika NoSQL-databaser tillgängliga för Java-utvecklare. Vissa JPA-implementeringar har utvecklats till att omfatta NoSQL, inklusive Hibernate OGM och EclipseLink.

Figur 1 illustrerar rollen för JPA och ORM-skiktet i applikationsutveckling.

JavaWorld /

Konfigurera Java ORM-lagret

När du skapar ett nytt projekt för att använda JPA måste du konfigurera datalagret och JPA-leverantören. Du konfigurerar en datalagringsanslutning för att ansluta till din valda databas (SQL eller NoSQL). Du kommer också att inkludera och konfigurera JPA-leverantören , som är ett ramverk som Hibernate eller EclipseLink. Medan du kan konfigurera JPA manuellt väljer många utvecklare att använda Spring's out-of-the-box-stöd. Se " JPA installation och installation " nedan för en demonstration av både manuell och fjäderbaserad JPA installation och installation.

Java-dataobjekt

Java Data Objects är ett standardiserat uthållighetsramverk som skiljer sig från JPA främst genom att stödja uthållighetslogik i objektet och genom dess långvariga stöd för att arbeta med icke-relationsdatabaser. JPA och JDO är tillräckligt lika för att JDO-leverantörer ofta också stöder JPA. Se Apache JDO-projektet för att lära dig mer om JDO i förhållande till andra uthållighetsstandarder som JPA och JDBC.

Datapersistens i Java

Ur ett programmeringsperspektiv är ORM-skiktet ett adapterlager : det anpassar språket för objektdiagram till språket i SQL och relationstabeller. ORM-skiktet gör det möjligt för objektorienterade utvecklare att bygga programvara som håller kvar data utan att någonsin lämna det objektorienterade paradigmet.

När du använder JPA skapar du en karta från datalagret till programmets datamodellobjekt. I stället för att definiera hur objekt sparas och hämtas definierar du kartläggningen mellan objekt och din databas och anropar sedan JPA för att bestå dem. Om du använder en relationsdatabas hanteras mycket av den faktiska anslutningen mellan din applikationskod och databasen av JDBC, Java Database Connectivity API.

Som specifikation tillhandahåller JPA metadataanteckningar som du använder för att definiera kartläggningen mellan objekt och databasen. Varje JPA-implementering ger sin egen motor för JPA-anteckningar. JPA-specifikationen tillhandahåller också PersistanceManagereller EntityManager, vilka är de viktigaste kontaktpunkterna med JPA-systemet (där din affärslogik kod berättar för systemet vad du ska göra med de mappade objekten).

För att göra allt detta mer konkret, överväg Listing 1, som är en enkel dataklass för modellering av en musiker.

Listing 1. En enkel dataklass i 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... } 

Den Musicianklass i Listing 1 används för att lagra data. Det kan innehålla primitiva data såsom namn fältet. Det kan också hålla relationer till andra klasser som mainInstrumentoch performances.

Musician's skäl för varelse är att innehålla data. Denna typ av klass kallas ibland ett DTO- eller dataöverföringsobjekt . DTO: er är ett vanligt inslag i mjukvaruutveckling. Även om de innehåller många typer av data, innehåller de ingen affärslogik. Att bestå dataobjekt är en allestädes närvarande utmaning inom mjukvaruutveckling.

Datapersistens med JDBC

Ett sätt att spara en instans av Musicianklassen i en relationsdatabas är att använda JDBC-biblioteket. JDBC är ett lager av abstraktion som låter en applikation utfärda SQL-kommandon utan att tänka på den underliggande databasimplementeringen.

Listning 2 visar hur du kan bestå Musicianklassen med JDBC.

Listing 2. JDBC infogar en post

 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 

Koden i Listing 2 är ganska självdokumenterande. Den georgeHarrisonobjektet kan komma från var som helst (front-end in extern service, etc.) och har sitt ID och namnfält in. Fälten på objektet används sedan för att leverera värdena för en SQL- insertsats. ( PreparedStatementKlassen är en del av JDBC och erbjuder ett sätt att säkert tillämpa värden på en SQL-fråga.)

Medan JDBC tillåter kontrollen som kommer med manuell konfiguration är det besvärligt jämfört med JPA. För att kunna ändra databasen måste du först skapa en SQL-fråga som mappar från ditt Java-objekt till tabellerna i en relationsdatabas. Du måste sedan ändra SQL när en objektsignatur ändras. Med JDBC blir underhåll av SQL en uppgift i sig.

Datapersistens med JPA

Tänk nu på Listing 3, där vi fortsätter Musicianklassen med JPA.

Listing 3. Ihållande George Harrison med JPA

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

Listing 3 ersätter manuell SQL från Listing 2 med en enda rad session.save(), som instruerar JPA att bestå objektet. Från och med då hanteras SQL-konverteringen av ramverket, så du behöver aldrig lämna det objektorienterade paradigmet.

Anmärkningar om metadata i JPA

Magiken i Listing 3 är resultatet av en konfiguration som skapas med JPA: s kommentarer. Utvecklare använder anteckningar för att informera JPA om vilka objekt som ska bestå och hur de ska bestå.

Listning 4 visar Musicianklassen med en enda JPA-kommentar.

Listning 4. JPA: s @Entity-anteckning

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

Slutligen Musiciankan ha en en-till-ett förhållande med en Quoteenhet, som används för att representera ett berömt citat: Quote famousQuote = new Quote().

Definiera relationstyper

JPA har anteckningar för var och en av sina typer av relationskartläggning. Listning 7 visar hur du kan anteckna förhållandet mellan en Musicianoch Performanceen.

Listning 7. Anmärkning av en-till-många-relation