Introduzione
In questo tutorial, parleremo di Hibernate e della Java Persistence API (JPA) – con particolare attenzione alle differenze tra loro.
Inizieremo esplorando cos’è JPA, come si usa e i concetti fondamentali che ci sono dietro.
Poi, daremo un’occhiata a come Hibernate ed EclipseLink si inseriscono nel quadro.
Object-Relational Mapping
Prima di immergerci in JPA, è importante capire il concetto di Object-Relational Mapping – conosciuto anche come ORM.
Object-relational mapping è semplicemente il processo di persistere qualsiasi oggetto Java direttamente in una tabella del database. Di solito, il nome dell’oggetto che viene persistito diventa il nome della tabella, e ogni campo all’interno di quell’oggetto diventa una colonna. Con la tabella impostata, ogni riga corrisponde a un record nell’applicazione.
Un’introduzione a JPA
La Java Persistence API, o JPA, è una specifica che definisce la gestione dei dati relazionali in un’applicazione Java. L’API traccia un insieme di concetti che definiscono quali oggetti all’interno dell’applicazione dovrebbero essere persistiti e come dovrebbero essere persistiti.
È importante notare che JPA è solo una specifica e che ha bisogno di un’implementazione per funzionare – ma ne parleremo più avanti.
Ora, discutiamo alcuni dei concetti fondamentali di JPA che un’implementazione deve coprire.
3.1. Entità
La classe javax.persistence.Entity definisce quali oggetti devono essere persistiti nel database. Per ogni entità persistita, JPA crea una nuova tabella nel database scelto.
Inoltre, tutte le entità scelte dovrebbero definire una chiave primaria denotata dall’annotazione @Id. Insieme all’annotazione @GeneratedValue, definiamo che la chiave primaria dovrebbe essere generata automaticamente quando il record è persistito nel database.
Diamo un’occhiata a un rapido esempio di un’entità descritta da JPA.
@Entitypublic class Car { @GeneratedValue @Id public long id; // getters and setters}
Ricordate, questo attualmente non avrà alcun effetto sull’applicazione – JPA non fornisce alcun codice di implementazione.
3.2. Persistenza dei campi
Un altro concetto centrale di JPA è la persistenza dei campi. Quando un oggetto in Java è definito come un’entità, tutti i campi al suo interno sono automaticamente persistiti come colonne diverse nella tabella delle entità.
Se c’è un campo all’interno di un oggetto persistente che non vogliamo persistere nel database, possiamo dichiarare il campo transitorio con l’annotazione @Transient.
3.3. Relazioni
In seguito, JPA specifica come dovremmo gestire le relazioni tra le diverse tabelle del database all’interno della nostra applicazione. Come abbiamo visto, JPA gestisce questo con le annotazioni. Ci sono quattro annotazioni di relazione che dobbiamo tenere a mente:
- @OneToOne
- @OneToMany
- @ManyToOne
- @ManyToMany
Diamo uno sguardo a come funziona:
@Entitypublic class SteeringWheel { @OneToOne private Car car // getters and setters}
Nel nostro esempio sopra, la classe SteeringWheel descrive una relazione uno a uno con la nostra classe Car di prima.
3.4. Entity Manager
Infine, la classe javax.persistence.EntityManager specifica le operazioni da e verso il database. EntityManager contiene le comuni operazioni Create, Read, Update e Delete (CRUD) che sono persistite nel database.
Implementazioni JPA
Con le specifiche JPA che definiscono come e cosa dobbiamo persistere, abbiamo ora bisogno di scegliere un fornitore di implementazione per fornire il codice necessario. Senza un tale fornitore, avremmo bisogno di implementare tutte le classi rilevanti per essere conformi a JPA, e questo è un sacco di lavoro!
Ci sono molti fornitori tra cui scegliere, ognuno con i suoi pro e contro. Quando si prende una decisione su quale usare, dovremmo considerare alcuni dei seguenti punti:
- Maturità del progetto – da quanto tempo esiste il provider e quanto è ben documentato?
- Sottoprogetti – il fornitore ha qualche sottoprogetto utile per la nostra nuova applicazione?
- Supporto della comunità – c’è qualcuno che ci aiuta quando ci ritroviamo con un bug critico?
- Benchmarking – quanto è performante l’implementazione?
Sebbene non andremo in profondità sul benchmarking dei diversi provider JPA, JPA Performance Benchmark (JPAB) contiene preziose informazioni al riguardo.
Detto questo, diamo una breve occhiata ad alcuni dei migliori provider di JPA.
Hibernate
Al suo interno, Hibernate è uno strumento di mappatura relazionale a oggetti che fornisce un’implementazione di JPA. Hibernate è una delle implementazioni JPA più mature in circolazione, con un’enorme comunità che sostiene il progetto.
Implementa tutte le classi javax.persistence che abbiamo visto in precedenza nell’articolo, oltre a fornire funzionalità oltre JPA – strumenti Hibernate, validazione e ricerca. Anche se queste API specifiche di Hibernate possono essere utili, non sono necessarie in applicazioni che richiedono solo le funzionalità di base di JPA.
Diamo una rapida occhiata a ciò che Hibernate offre con l’annotazione @Entity.
Sempre rispettando il contratto JPA, @org.hibernate.annotations.Entity aggiunge ulteriori metadati che vanno oltre le specifiche JPA. Questo permette di mettere a punto la persistenza delle entità. Per esempio, guardiamo alcune annotazioni offerte da Hibernate che estendono la funzionalità di @Entity:
- @Table – ci permette di specificare il nome della tabella creata per l’entità
- @BatchSize – specifica la dimensione del batch quando si recuperano le entità dalla tabella
Vale anche la pena notare alcune delle caratteristiche extra che il JPA non specifica, che possono rivelarsi utili in applicazioni più grandi:
- Dichiarazioni CRUD personalizzabili con le annotazioni @SQLInsert, @SQLUpate e @SQLDelete
- Supporto per la cancellazione soft
- Entità immutabili con l’annotazione @Immutable
Per un’immersione più profonda nella persistenza di Hibernate e Java – vai alla nostra serie di tutorial sulla persistenza di Spring.
EclipseLink
EclipseLink, costruito dalla Eclipse Foundation, fornisce un’implementazione JPA open-source. Inoltre, EclipseLink supporta una serie di altri standard di persistenza come Java Architecture for XML Binding (JAXB).
In parole povere, piuttosto che persistere un oggetto in una riga di database, JAXB lo mappa in una rappresentazione XML.
Poi, confrontando la stessa implementazione dell’annotazione @Entity, vediamo che EclipseLink offre nuovamente diverse estensioni. Mentre non c’è un’annotazione per @BatchSize come abbiamo visto prima, EclipseLink offre altre opzioni che Hibernate non offre.
Per esempio:
- @ReadOnly – specifica che l’entità da persistere è di sola lettura
- @Struct – definisce la classe da mappare su un tipo di database ‘struct’
Per saperne di più su ciò che EclipseLink ha da offrire, vai alla nostra guida su EclipseLink con Spring.
Conclusione
In questo articolo, abbiamo visto la Java Persistence API, o JPA.
Infine, abbiamo esplorato come differisce da Hibernate e EclipseLink.