Che cos’è JPA? Introduzione all’API di persistenza Java

Come specifica, l’API di persistenza Java riguarda la persistenza, che indica liberamente qualsiasi meccanismo con cui gli oggetti Java sopravvivono al processo applicativo che li ha creati. Non tutti gli oggetti Java devono essere mantenuti, ma la maggior parte delle applicazioni persistono oggetti business chiave. La specifica JPA consente di definire quali oggetti devono essere mantenuti e come tali oggetti devono essere mantenuti nelle applicazioni Java.

Di per sé, JPA non è uno strumento o un framework; piuttosto, definisce un insieme di concetti che possono essere implementati da qualsiasi strumento o framework. Mentre il modello ORM (Object-Relational Mapping) di JPA era originariamente basato su Hibernate, da allora si è evoluto. Allo stesso modo, mentre JPA era originariamente destinato all’uso con database relazionali/SQL, alcune implementazioni JPA sono state estese per l’uso con datastore NoSQL. Un framework popolare che supporta JPA con NoSQL è EclipseLink, l’implementazione di riferimento per JPA 2.2.

JPA e Hibernate

A causa della loro storia intrecciata, Hibernate e JPA sono spesso confuse. Tuttavia, come la specifica Java Servlet, JPA ha generato molti strumenti e framework compatibili; Hibernate è solo uno di questi.

Sviluppato da Gavin King e rilasciato all’inizio del 2002, Hibernate è una libreria ORM per Java. King ha sviluppato Hibernate come alternativa ai bean di entità per la persistenza. Il framework era così popolare, e così necessario all’epoca, che molte delle sue idee furono adottate e codificate nella prima specifica JPA.

Oggi, Hibernate ORM è una delle implementazioni JPA più mature e ancora un’opzione popolare per ORM in Java. Ibernazione ORM 5.3.8 (la versione corrente al momento della stesura) implementa JPA 2.2. Inoltre, la famiglia di strumenti di Hibernate si è ampliata per includere strumenti popolari come Hibernate Search, Hibernate Validator e Hibernate OGM, che supporta la persistenza del modello di dominio per NoSQL.

Che cos’è Java ORM?

Mentre differiscono nell’esecuzione, ogni implementazione JPA fornisce una sorta di livello ORM. Per comprendere gli strumenti compatibili con JPA e JPA, è necessario avere una buona conoscenza di ORM.

Object-relational mapping è un’attività che gli sviluppatori hanno buone ragioni per evitare di fare manualmente. Un framework come Hibernate ORM o EclipseLink codifica quell’attività in una libreria o framework, un livello ORM. Come parte dell’architettura dell’applicazione, il livello ORM è responsabile della gestione della conversione degli oggetti software per interagire con le tabelle e le colonne in un database relazionale. In Java, il livello ORM converte le classi e gli oggetti Java in modo che possano essere memorizzati e gestiti in un database relazionale.

Per impostazione predefinita, il nome dell’oggetto che viene mantenuto diventa il nome della tabella e i campi diventano colonne. Una volta impostata la tabella, ogni riga della tabella corrisponde a un oggetto nell’applicazione. La mappatura degli oggetti è configurabile, ma i valori predefiniti tendono a funzionare bene.

Figura 1 illustra il ruolo di JPA e il livello ORM nello sviluppo di applicazioni.

JavaWorld / IDG

Figura 1. JPA e il livello ORM

Configurazione del livello ORM Java

Quando si imposta un nuovo progetto per utilizzare JPA, è necessario configurare il datastore e il provider JPA. Potrai configurare un connettore datastore per connettersi al database scelto (SQL o NoSQL). Includerai e configurerai anche il provider JPA, che è un framework come Hibernate o EclipseLink. Mentre è possibile configurare JPA manualmente, molti sviluppatori scelgono di utilizzare il supporto out-of-the-box di Spring. Vedere “Installazione e configurazione JPA” di seguito per una dimostrazione di installazione e configurazione JPA manuale e a molla.

Persistenza dei dati in Java

Dal punto di vista della programmazione, il livello ORM è un livello adattatore: adatta il linguaggio dei grafici oggetto al linguaggio delle tabelle SQL e relazionali. Il livello ORM consente agli sviluppatori orientati agli oggetti di creare software che persistono i dati senza mai uscire dal paradigma orientato agli oggetti.

Quando si utilizza JPA, si crea una mappa dall’archivio dati agli oggetti del modello di dati dell’applicazione. Invece di definire come gli oggetti vengono salvati e recuperati, si definisce la mappatura tra gli oggetti e il database, quindi invocare JPA per mantenerli. Se si utilizza un database relazionale, gran parte della connessione effettiva tra il codice dell’applicazione e il database verrà gestita da JDBC, l’API di connettività del database Java.

Come specifica, JPA fornisce annotazioni di metadati, che si utilizzano per definire la mappatura tra gli oggetti e il database. Ogni implementazione JPA fornisce il proprio motore per le annotazioni JPA. La specifica JPA fornisce anchePersistanceManager oEntityManager, che sono i punti chiave di contatto con il sistema JPA (in cui il codice di logica aziendale indica al sistema cosa fare con gli oggetti mappati).

Per rendere tutto ciò più concreto, considera il listato 1, che è una semplice classe di dati per modellare un musicista.

Elenco 1. Una semplice classe di dati in Java

La classeMusician nel listato 1 viene utilizzata per contenere i dati. Può contenere dati primitivi come il campo nome. Può anche contenere relazioni con altre classi come mainInstrumenteperformances.

Musician‘s ragione per essere è quello di contenere i dati. Questo tipo di classe è talvolta noto come DTO o oggetto di trasferimento dati. I DTO sono una caratteristica comune dello sviluppo del software. Mentre detengono molti tipi di dati, non contengono alcuna logica di business. La persistenza degli oggetti dati è una sfida onnipresente nello sviluppo del software.

Persistenza dei dati con JDBC

Un modo per salvare un’istanza della classeMusician in un database relazionale sarebbe quello di utilizzare la libreria JDBC. JDBC è un livello di astrazione che consente a un’applicazione di emettere comandi SQL senza pensare all’implementazione del database sottostante.

Il listato 2 mostra come è possibile mantenere la classe Musician usando JDBC.

Elenco 2. JDBC inserimento di un record

Il codice nel listato 2 è abbastanza auto-documentante. L’oggettogeorgeHarrison potrebbe provenire da qualsiasi luogo (invio front-end,servizio esterno, ecc.), e ha i suoi campi ID e nome impostati. I campi sull’oggetto vengono quindi utilizzati per fornire i valori di un’istruzione SQL insert. (La classePreparedStatement fa parte di JDBC, offrendo un modo per applicare in modo sicuro i valori a una query SQL.)

Mentre JDBC consente il controllo fornito con la configurazione manuale, è ingombrante rispetto a JPA. Per modificare il database, è necessario innanzitutto creare una query SQL che associ l’oggetto Java alle tabelle di un database relazionale. È quindi necessario modificare l’SQL ogni volta che cambia la firma di un oggetto. Con JDBC, mantenere l’SQL diventa un’attività in sé.

Persistenza dei dati con JPA

Ora considera il listato 3, dove persistiamo la classeMusician usando JPA.

Elenco 3. Persisting George Harrison con JPA

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

Listato 3 sostituisce il manuale SQL dal listato 2 con una singola riga,session.save(), che indica a JPA di mantenere l’oggetto. Da quel momento in poi, la conversione SQL viene gestita dal framework, quindi non devi mai lasciare il paradigma orientato agli oggetti.

Annotazioni di metadati in JPA

La magia nel listato 3 è il risultato di una configurazione, che viene creata usando le annotazioni di JPA. Gli sviluppatori utilizzano le annotazioni per informare JPA quali oggetti devono essere mantenuti e come devono essere mantenuti.

Il listato 4 mostra la classeMusician con una singola annotazione JPA.

Elenco 4. JPA @ Entity annotation

@Entitypublic class Musician { // ..class body}

Gli oggetti persistenti sono talvolta chiamati entità. Associare@Entity a una classe comeMusician informa JPA che questa classe e i suoi oggetti devono essere mantenuti.

Configurazione di JPA

Come la maggior parte dei framework moderni, JPA abbraccia la codifica per convenzione (nota anche come convenzione sulla configurazione), in cui il framework fornisce una configurazione predefinita basata sulle best practice del settore. Ad esempio, una classe denominata Musician verrebbe mappata per impostazione predefinita a una tabella di database denominata Musician.

La configurazione convenzionale è un risparmio di tempo, e in molti casi funziona abbastanza bene. È anche possibile personalizzare la configurazione JPA. Ad esempio, è possibile utilizzare l’annotazione @Table di JPA per specificare la tabella in cui deve essere memorizzata la classe Musician.

Elenco 5. L’annotazione @ Table di JPA

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

Listato 5 indica a JPA di mantenere l’entità (Musician classe) nella tabellamusician.

Chiave primaria

In JPA, la chiave primaria è il campo utilizzato per identificare in modo univoco ogni oggetto nel database. La chiave primaria è utile per fare riferimento e mettere in relazione gli oggetti ad altre entità. Ogni volta che si memorizza un oggetto in una tabella, si specifica anche il campo da utilizzare come chiave primaria.

Nel listato 6, diciamo a JPA quale campo usare come chiave primaria di Musician.

Elenco 6. Specificare la chiave primaria

@Entitypublic class Musician { @Id private Long id;

In questo caso, abbiamo usato l’annotazione di JPA@Idper specificare il campoidcomeMusician. Per impostazione predefinita, questa configurazione presuppone che la chiave primaria venga impostata dal database, ad esempio quando il campo è impostato su incremento automatico sulla tabella.

JPA supporta altre strategie per generare la chiave primaria di un oggetto. Ha anche annotazioni per cambiare i nomi dei singoli campi. In generale, JPA è abbastanza flessibile da adattarsi a qualsiasi mappatura di persistenza di cui potresti aver bisogno.

CRUD operations

Una volta mappata una classe a una tabella di database e stabilita la sua chiave primaria, hai tutto il necessario per creare, recuperare, eliminare e aggiornare quella classe nel database. Chiamare session.save() creerà o aggiornerà la classe specificata, a seconda che il campo della chiave primaria sia null o si applichi a en entità esistente. Chiamando entityManager.remove() cancellerà la classe specificata.

Relazioni di entità in JPA

La semplice persistenza di un oggetto con un campo primitivo è solo metà dell’equazione. JPA ha anche la capacità di gestire le entità in relazione tra loro. Quattro tipi di relazioni di entità sono possibili sia nelle tabelle che negli oggetti:

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

Ogni tipo di relazione descrive come un’entità si relaziona con altre entità. Ad esempio, l’entitàMusician potrebbe avere una relazione uno-a-molti conPerformance, un’entità rappresentata da una raccolta comeList oSet.

Se il Musician includeva un campo Band, la relazione tra queste entità potrebbe essere many-to-one, implicando la raccolta di Musiciansul singolo Band classe. (Supponendo che ogni musicista si esibisca solo in una singola band.)

If Musicianincludeva un campo BandMates, che poteva rappresentare una relazione molti-a-molti con altre entità Musician.

Infine, Musician potrebbe avere una relazione uno-a-uno con un’entità Quote, utilizzata per rappresentare una citazione famosa: Quote famousQuote = new Quote().

Definizione dei tipi di relazione

JPA ha annotazioni per ciascuno dei suoi tipi di mappatura delle relazioni. Il listato 7 mostra come si potrebbe annotare la relazione uno-a-molti traMusician ePerformances.

Listato 7. Annotazione di una relazione uno-a-molti

Una cosa da notare è che@JoinColumndice a JPA quale colonna della tabella delle prestazioni verrà mappata all’entitàMusician. Ogni performance sarà associata a un singoloMusician, che viene monitorato da questa colonna. Quando JPA carica un Musician o un Performance nel database, utilizzerà queste informazioni per ricostituire il grafico dell’oggetto.

Recupero delle strategie in JPA

Oltre a sapere dove posizionare le entità correlate nel database, JPA deve sapere come si desidera caricarle. Le strategie di recupero indicano a JPA come caricare le entità correlate. Quando si caricano e si salvano oggetti, un framework JPA deve fornire la possibilità di ottimizzare la gestione dei grafici degli oggetti. Ad esempio, se la classe Musician ha un campo bandMate (come mostrato nel listato 7), caricare george potrebbe causare il caricamento dell’intera tabella Musician dal database!

Ciò che è necessario è la capacità di definire il caricamento pigro di entità correlate-riconoscendo, ovviamente, che le relazioni in JPA possono essere desiderose o pigre. È possibile utilizzare le annotazioni per personalizzare il recupero di strategie, ma JPA, la configurazione predefinita spesso funziona out of the box, senza modifiche:

  1. Uno-a-molti: Lazy
  2. Molti-a-uno: Desideroso
  3. molti-a-Molti: Lazy
  4. uno-a-Uno: Desideroso

JPA installazione e setup

Ci concludere con un rapido sguardo alla installazione e configurazione dell’APP per le applicazioni Java. Per questa dimostrazione userò EclipseLink, l’implementazione di riferimento JPA.

Il modo comune per installare JPA è includere un provider JPA nel progetto. Il listato 8 mostra come includeresti EclipseLink come dipendenza nel tuo file Maven pom.xml.

Elenco 8. Includi EclipseLink come dipendenza Maven

org.eclipse.persistenceeclipselink2.5.0-RC1

Dovrai anche includere il driver per il tuo database, come mostrato nel Listato 9.

Elenco 9. Dipendenza Maven per un connettore MySQL

mysqlmysql-connector-java5.1.32

Successivamente, dovrai comunicare al sistema il tuo database e il tuo provider. Questo viene fatto nel filepersistence.xml, come mostrato nel listato 10.

Elenco 10. Persistenza.xml

Esistono altri modi per fornire queste informazioni al sistema, anche a livello di codice. Raccomando di utilizzare il filepersistence.xml perché la memorizzazione delle dipendenze in questo modo rende molto facile aggiornare l’applicazione senza modificare il codice.

Spring configuration for JPA

L’utilizzo di Spring faciliterà notevolmente l’integrazione di JPA nell’applicazione. Ad esempio, posizionare l’annotazione@SpringBootApplication nell’intestazione dell’applicazione indica a Spring di eseguire automaticamente la scansione delle classi e iniettareEntityManager come richiesto, in base alla configurazione specificata.

Il listato 11 mostra le dipendenze da includere se si desidera il supporto JPA di Spring per la propria applicazione.

Elenco 11. Aggiunta del supporto Spring JPA in Maven

Conclusione

Ogni applicazione che si occupa di un database dovrebbe definire un livello di applicazione il cui unico scopo è isolare il codice di persistenza. Come hai visto in questo articolo, l’API di persistenza Java introduce una serie di funzionalità e supporto per la persistenza degli oggetti Java. Le applicazioni semplici potrebbero non richiedere tutte le funzionalità di JPA e, in alcuni casi, il sovraccarico della configurazione del framework potrebbe non essere meritato. Man mano che un’applicazione cresce, tuttavia, la struttura e l’incapsulamento di JPA guadagnano davvero il loro mantenimento. L’utilizzo di JPA mantiene il codice oggetto semplice e fornisce un framework convenzionale per l’accesso ai dati nelle applicazioni Java.

Scopri di più sull’API di persistenza Java e sulle tecnologie correlate

  • Che cos’è JDBC? Introduzione alla connettività del database Java: scopri le API di basso livello di Java per la connessione a un database, l’emissione di query SQL e altro ancora.
  • Persistenza Java con JPA e Hibernate, Parte 1: Entità e relazioni: Inizia a modellare entità e relazioni con Java 8 e Hibernate ORM.
  • Persistenza Java con JPA e Hibernate, Parte 2: Pratica pratica modellazione di relazioni molti-a-molti e relazioni di ereditarietà in Java 8 e Hibernate ORM.
  • Implementazione del comportamento dipendente dallo stato: una classica introduzione al modello di stato e alla dipendenza dallo stato in Java.
  • Eager / Lazy Loading In Hibernate: Come applicare eager e lazy loading in Hibernate.
  • JPA 2.2 porta alcune modifiche molto attese: una panoramica degli aggiornamenti delle specifiche in JPA 2.2, inclusi miglioramenti al CDI, un migliore allineamento con l’API Data e ora e il supporto per @Repeatable annotazioni.
  • Dovresti usare JPA per il tuo prossimo progetto?: Domande chiave che potrebbero aiutarti a decidere.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *