(hibernate).

Transcript

(hibernate).
Tecnologie Web T
Metodologie di Progettazione della Persistenza:
Approccio “forza bruta”, Pattern DAO,
Framework ORM e Hibernate
Home Page del corso: http://www-db.disi.unibo.it/courses/TW/
Versione elettronica: 4.02.MetodologieProgettazionePersistenza.pdf
Versione elettronica: 4.02.MetodologieProgettazionePersistenza-2p.pdf
DAO, ORM e Hibernate
1
Gestione della persistenza
 Le nostre applicazioni sono sviluppate con linguaggi OO
(lo stesso vale anche per i moderni sistemi informativi)
mentre la persistenza dei dati è affidata ai DBMS relazionali
 OO: scalabilità e riusabilità
 RDBMS: affidabilità, efficienza, efficacia
 Esistono differenze significative tra queste due tecnologie:
 differenze tecnologiche
 differenze culturali
 Si parla di conflitto di impedenza
DAO, ORM e Hibernate
2
Conflitto di impedenza (1/4)
 Definito anche come “disaccoppiamento di impedenza”
(o impedance mismatch) tra base di dati e linguaggio
 linguaggi: operazioni su singole variabili o oggetti
 SQL: operazioni su relazioni (insiemi di ennuple)
 Differenze di accesso ai dati e correlazione:
 linguaggio: dipende dal paradigma e dai tipi disponibili;
ad esempio scansione di liste o “navigazione” tra oggetti
 SQL: join (ottimizzabile)
DAO, ORM e Hibernate
3
Conflitto di impedenza (2/4)
 Differenze sui tipi di dato primitivi:
 linguaggi: numeri, stringhe, booleani
 SQL: CHAR, VARCHAR, DATE, ...
 Differenze sui costruttori di tipo:
 linguaggio: dipende dal paradigma
 SQL: relazioni e ennuple
 OID (trasparenti al programmatore) vs. chiavi primarie
(visibili e manipolabili)
 Riferimenti vs. chiavi esterne
 Ereditarietà (senza controparte nel mondo relazionale)
DAO, ORM e Hibernate
4
Conflitto di impedenza (3/4)
 In generale, i dati risiedono nel database (DB) mentre la
logica applicativa viene implementata da oggetti
 Dal modello concettuale si può derivare (una prima
versione di)
 classi che implementano la logica applicativa (diciamo
che queste classi implementano il modello di dominio, o
più semplicemente il modello)
 classi facade che offrono le operazioni (metodi)
dell’applicazione
 schema relazionale per memorizzare i dati
 questa attività può essere fatta anche successivamente
 in alcuni casi (sistemi legacy) il database potrebbe esistere già e
potrebbe non essere modificabile
• quindi tutte le attività di progetto sono condizionate da questo vincolo
DAO, ORM e Hibernate
5
Conflitto di impedenza (4/4)
 I dati sono memorizzati in maniera persistente nel DB
 A seconda del punto di vista
(sviluppatore OO vs. DB Administrator - DBA)
 “Gli oggetti in memoria possono essere visti come una
copia di una porzione del database”
 “Il database può essere visto come un supporto su cui
memorizzare in maniera persistente i dati del modello”
 Il conflitto di impedenza investe anche
aspetti "culturali" 
DAO, ORM e Hibernate
6
Metodologie per la gestione della persistenza
 In generale possiamo pensare che le operazioni (metodi)
degli oggetti facade
 caricano tuple dalla base di dati e le usano per creare gli
oggetti del modello
 effettuano le operazioni della logica applicativa
(es. evadi ordine)
 salvano in maniera persistente gli oggetti del modello
nella base di dati
 L'interazione con il DB è una operazione critica: esistono
diverse metodologie (di complessità crescente) per
realizzare questa interazione
 forza bruta
 pattern DAO
 framework ORM (e in particolare per noi Hibernate)
DAO, ORM e Hibernate
7
Forza bruta
 È la tecnica più semplice per gestire la persistenza
 forte accoppiamento con la sorgente dati
 Consiste nello scrivere dentro le classi del modello un
insieme di metodi che implementano le operazioni CRUD
 Operazioni CRUD
 Create: inserimento di una tupla (che rappresenta un oggetto) nel
database (INSERT)
 Retrieve: ricerca di una tupla secondo un qualche criterio di ricerca
(SELECT)
 Update: aggiornamento di una tupla nel database (UPDATE)
 Delete: eliminazione di una tupla nel database (DELETE)
 Ci possono essere diverse operazioni di Retrieve
 diversi criteri: “per chiave” vs. “per attributo” (es. ricerca cliente per
codice, per nome, etc.)
 diversi risultati (un oggetto, una collezione di oggetti) a seconda del
criterio
DAO, ORM e Hibernate
8
Forza bruta in sintesi (1/2)
 Per ogni classe MyC che rappresenta una entità del
dominio, si definiscono:
 un metodo doRetrieveByKey(X key) che
 restituisce un oggetto istanza di MyC i cui dati sono letti
dal database
• tipicamente da una tabella che è stata derivata dalla stessa
classe del modello di dominio che ha dato origine a MyC
 recupera i dati per chiave
 un metodo saveOrUpdate(…) che salva i dati
dell'oggetto corrente nel database
 il metodo esegue una istruzione SQL update o insert a
seconda che l'oggetto corrente esista già o meno nel
database
DAO, ORM e Hibernate
9
Forza bruta in sintesi (2/2)
 uno o più metodi doRetrieveByCond(…) che
restituiscono una collezione di oggetti istanza della
classe MyC che soddisfano una qualche condizione
(basata sui parametri del metodo)
 un metodo doDelete(…) che cancella dal database i
dati dell'oggetto corrente
DAO, ORM e Hibernate
10
Il pattern Data Access Object
 La soluzione Forza bruta non è particolarmente
conveniente
 L'accoppiamento tra la sorgente dati e le classi del
modello è molto forte
 Le classi del modello sono poco coese (responsabilità
eterogenee)
 Molto difficile iniziare a sviluppare senza preoccuparsi di
tanti (troppi !) dettagli e senza un ambiente operativo
complesso (java + dbms)
 Una soluzione "naturale" è quella di affidare le
responsabilità di interagire con il database ad opportune
classi
 Questo è l'approccio suggerito dal pattern
Data Access Object (DAO)
DAO, ORM e Hibernate
11
Il pattern DAO
 Un pattern è un “modo di fare le cose” che si è dimostrato
efficace e che per questo si tende ad applicare di nuovo
 Il pattern DAO è uno degli standard “J2EE design patterns”;
rappresenta un possibile modo di separare:
 logica di business (es: Servlet, JSP, …)
 logica di persistenza (es: r/w su DB, …)
 Infatti, i componenti della logica di business non dovrebbero
mai contenere codice che accede direttamente al database!
 scarsa manutenibilità
 sovrapposizione di responsabilità
 Solo gli oggetti previsti dal pattern DAO
 hanno il permesso di “vedere” il DB
 espongono metodi di accesso per tutti gli altri componenti
DAO, ORM e Hibernate
12
DAO: Caratteristiche principali (1/2)
 I valori scambiati tra DB e il resto dell’applicazione sono
racchiusi in oggetti detti Data Transfer Object (DTO):
 campi privati per contenere i dati da leggere/scrivere su
db
 metodi getter e setter per accedere dall’esterno a tali
campi
 metodi di utilità (confronto, stampa, …)
 Le operazioni che coinvolgono tali oggetti sono raggruppati
in interfacce che definiscono i Data Access Object (DAO)
disponibili:
 metodi CRUD
 altri metodi
DAO, ORM e Hibernate
13
DAO: Caratteristiche principali (2/2)
 Le implementazioni di tali interfacce (spesso indicate come
oggetti DAO, per brevità) permettono l’effettivo accesso al
database
 diverse implementazione possono permettere (e rendere
uniforme) l'accesso a DB di diversi vendor
 anche se si fa uso di un solo database, tale separazione
migliora comunque la divisione delle responsabilità tra le
parti dell’applicazione
 diventa facile migrare l’applicazione su DB diversi
 Gli oggetti DAO non sono istanziati direttamente dai
componenti, ma:
 possono essere ottenuti attraverso metodi factory
DAO, ORM e Hibernate
14
Pattern DAO con classi Factory
 Una unica factory astratta
 fornisce specifiche per le factory concrete
 espone un metodo creazionale parametrico per ottenere
factory concrete
 Una factory concreta per ogni tipo di DB supportato
 permette di ottenere oggetti DAO appropriati al
corrispondente tipo di DB
 può gestire aspetti quali ottenimento della connessione,
autenticazione, ...
 Un oggetto DTO per ogni tipo di entità che si vuole
rappresentare
 Una interfaccia DAO per ogni oggetto DTO
 Una implementazione dell'interfaccia DAO di un DTO per
ciascun DB supportato
DAO, ORM e Hibernate
15
Pattern DAO con classi Factory
DAO, ORM e Hibernate
16
Pattern DAO con classi Factory: Diagramma di sequenza
DAO, ORM e Hibernate
17
Pattern DAO: Struttura
DAO, ORM e Hibernate
18
Pattern DAO: Diagramma di sequenza
DAO, ORM e Hibernate
19
DAO in pratica
 Per ogni classe Entità del modello di dominio creiamo
(in un opportuno package) una interfaccia DAOEntità
con (le signature dei) metodi che realizzano le operazioni
CRUD
 Queste interface sono implementate da classi
(organizzate in opportuni package)
 questa scomposizione permette maggiore flessibilità
DAO, ORM e Hibernate
20
Caso di studio (UML)
Prodotto
CodiceProdotto
1
*
RigaOrdine
Nome
Quantità
Descrizione
NumeroLinea
Ordine
*
1
CodiceOrdine
Data
stato
Costo
*
1
Cliente
CodiceCliente
Nome
Indirizzo
DAO, ORM e Hibernate
21
Esempio: ProdottoDAO
public interface ProdottoDAO {
public List<Prodotto> doRetrieveAll()
throws PersistenceException;
public Prodotto doRetriveByKey(String codice)
throws PersistenceException;
public void saveOrUpdate(Prodotto prodotto)
throws PersistenceException;
public void delete(Prodotto prodotto)
throws PersistenceException;
// eventuali altri doRetriveBy...
}
DAO, ORM e Hibernate
22
Esempio: ProdottoDAOImpl
public class ProdottoDAOImpl implements ProdottoDAO {
public List<Prodotto> doRetrieveAll()
throws PersistenceException {
Connection connection = null;
List<Prodotto> prodotti;
…
try {
…
} catch (SQLException sqle) {
throw new PersistenceException(sqle);
} finally {
…
}
return prodotti;
}
…
}
DAO, ORM e Hibernate
23
Interazione Facade-DAO: Esempio
ProdottoDAO
Facade
ProdottoDB2DAO
DB2
Prodotto
DAO, ORM e Hibernate
24
Mettiamo ordine al codice
 Abbiamo classi per il modello, classi per la persistenza,
classi di utilità
 classi del modello nel package modello
 interfacce DAO nel package persistenza
 implementazioni (dbms dependant) dei DAO in
package persistenza.db2
 classi di utilità nel package util
DAO, ORM e Hibernate
25
Nota terminologica
 Le classi del modello implementano le entità del modello
concettuale, ed è bene che rispettino le seguenti
convenzioni:
 tutte le proprietà devono essere private
 per ogni proprietà: metodi setter e getter pubblici
 costruttore no-arg visibile
 Una classe che rispetta queste convenzioni viene chiamata
java bean
 Rispetto al nostro caso di studio, le nostre classi
Cliente, Prodotto, Ordine, RigaOrdine
sono bean
DAO, ORM e Hibernate
26
Caso di studio
package modello;
import java.util.*;
import persistenza.*;
public class FacadeImpl implements Facade {
private ClienteDAO clienteDao;
….
public Facade() {
clienteDao = new ClienteDAOImpl();
}
public void inserisciClienteNellaAnagrafica(Cliente cliente) throws ClienteException {
try {
clienteDao.saveOrUpdate(cliente);
} catch (PersistenceException e) {
throw new ClienteException("Exception in ClientiFacade while creating cliente.");
}
}
public List<Cliente> anagraficaClienti(){
try {
return clienteDao.doRetrieveClienteAll();
} catch (PersistenceException e) {
throw new ClienteException("Exception in ClientiFacade while retrieving cliente.", e);
}
}
public Cliente trovaClientePerCodice(String codiceCliente){
try {
return clienteDao.doRetrieveClienteByCodice(codiceCliente);
} catch (PersistenceException e) {
throw new ClienteException("Exception in ClientiFacade while retrieving cliente"+ codiceCliente +, e);
}
}
…
}
ORM e Hibernate
27
Soluzioni al conflitto di impedenza
 Analizziamo ora i principali problemi dovuti al conflitto di
impedenza e ne presentiamo le soluzioni
 A scopo didattico lavoriamo su DAO, ma le considerazioni
che facciamo seguendo questa soluzione hanno validità
generale!!
 Al termine del trattamento generale delle problematiche
relative al conflitto di impedenza, concluderemo la gestione
della persistenza illustrando la metodologia Object
Relational Mapping (ORM) e una sua diretta
implementazione, ovvero il framework Hibernate
DAO, ORM e Hibernate
28
Risolvere il conflitto di impedenza
 Nel modello OO, le relazioni tra oggetti sono realizzate con
riferimenti, mentre nel modello relazionale sono realizzate
con i valori
 Vediamo problemi e soluzioni relativamente a:
 Retrieve: dal DB agli oggetti
(ricostruzione degli oggetti a partire da dati persistenti)
 Create: dagli oggetti al DB
(memorizzazione persistente degli oggetti nel DB)
DAO, ORM e Hibernate
29
Retrieve: Ricostruzione degli oggetti dal DB
 Il problema principale nel ricostruire oggetti a partire dalla
base di dati consiste nel ricostruire i riferimenti
 Forze in gioco
 chiavi esterne contro riferimenti
 join (operazione "non direzionale") contro navigazioni
DAO, ORM e Hibernate
30
Caso di studio
Prodotto
CodiceProdotto
Nome
Descrizione
1
*
RigaOrdine
Quantità
Ordine
*
NumeroLinea
Costo
1
CodiceOrdine
Data
stato
*
1
Cliente
CodiceCliente
Nome
Indirizzo
DAO, ORM e Hibernate
31
Ricostruzione degli oggetti dal DB
 Consideriamo la ricostruzione di un oggetto Ordine,
ad esempio, per definire il metodo
Ordine doRetrieveOrdineByKey(String codice)
 nella classe Ordine:
 una collezione di riferimenti a oggetti RigaOrdine
• ogni riga ordine ha un riferimento ad un oggetto Prodotto
 un riferimento ad un oggetto della classe Cliente
 nel database:
 tabella ORDINI (ha una foreign key (FK) con CLIENTI)
 tabella RIGHEORDINE (FK con ORDINI, FK con PRODOTTI)
 tabella CLIENTI
 Per ricostruire un oggetto Ordine "completo" devo
ricostruire la collezione di oggetti RigaOrdine e
l'oggetto Cliente (e anche questi oggetti devono essere
"completi"?!)
DAO, ORM e Hibernate
32
Ricostruzione degli oggetti dal DB
 Per ora, a fini didattici, non preoccupiamoci del riferimento
Cliente: successivamente ci preoccupiamo anche di
questo
 Come ricostruiamo l'oggetto Ordine?
 eseguo un join tra le tabelle ORDINI e RIGHEORDINE
 itero sul ResultSet e costruisco i vari oggetti Ordine e
RigaOrdine opportunamente collegati
DAO, ORM e Hibernate
33
Nota
 Eseguo un join tra le tabelle ORDINI e RIGHEORDINE
 Che join usiamo?
 è possibile che nella tabella ORDINI ci siano tuple per le
quali non ci sono righe nella tabella RIGHE_ORDINE?
 se la risposta è SI, allora devo usare un outer join
DAO, ORM e Hibernate
34
Un inciso
 Potrebbe sembrare più semplice evitare di effettuare un
join, usando due SELECT e gestendone i risultati nel
codice Java:
 cerco nella tabella ORDINI del database l'ordine con l'id
richiesto e costruisco un oggetto Ordine
 cerco nella tabella RIGHEORDINE del database le tuple che
hanno come chiave esterna l'id dell'oggetto Ordine del punto
precedente e con esse costruisco una collezione di oggetti
RigaOrdine
 aggiungo la collezione di righe ordine all'oggetto Ordine
 Commenti:
 (apparentemente) il codice per costruire l'oggetto Ordine è
più semplice (ma se sapete usare le collezioni il problema
non si pone più di tanto…)
 ma i DBMS sono ottimizzati per effettuare efficientemente
join!
DAO, ORM e Hibernate
35
Ricostruzione degli oggetti dal DB
 Ma che cosa è un "oggetto completo"?
 con un modello di dominio complesso questa strategia
può portarci a caricare una rete molto vasta di oggetti
 esempio:
ClienteOrdineRigaOrdineProdottoFornitore
 Fino a quando devo costruire oggetti
"inseguendo i riferimenti” ?
DAO, ORM e Hibernate
36
Ricostruzione degli oggetti dal DB
 Possiamo dare una risposta a queste domande
analizzando i casi d'uso e il modello del dominio
 In particolare l'inseguimento dei riferimenti tra oggetti è
guidato dalle operazioni offerte dal sistema
 Nel progettare le classi, i riferimenti vanno messi
considerando la direzione in cui le corrispondenti
associazioni sono navigate dalle operazioni del sistema
! questo aspetto non ha rilevanza nella progettazione del
database, perché i riferimenti sono implementati tramite
valori e l'operatore di join non è direzionale
DAO, ORM e Hibernate
37
Ricostruzione degli oggetti dal DB
 E quando non ha senso costruire un oggetto completo,
come mi comporto?
 i metodi che richiedono l'inseguimento di un riferimento, se
invocati devono restituire l'oggetto corretto!
• In questo caso ricorriamo ad una tecnica, detta
Caricamento Pigro, implementata tramite l'applicazione del
Pattern Proxy
DAO, ORM e Hibernate
38
Lazy Load (caricamento pigro)
 Consideriamo la classe Cliente: l'associazione con
l'Ordine è bidirezionale
 Tuttavia non è ragionevole pensare che per caricare i dati
di un cliente si debba ricostruire l'intera rete di oggetti (fino
a Prodotto!?)
 Possiamo pensare che gli ordini associati al cliente
possano essere caricati solo quando richiesti:
 quando invochiamo il metodo getOrdini() su un
oggetto Cliente
 Questa strategia si chiama Lazy Load (caricamento pigro)
DAO, ORM e Hibernate
39
Lazy Load (caricamento pigro)
 In pratica quello che vogliamo fare è caricare i dati solo
quando questi sono effettivamente richiesti
 Vediamo come dovrebbe agire il metodo getOrdini()
della classe Cliente seguendo questa strategia
 quando invocato per la prima volta, il metodo getOrdini()
esegue la query per costruire gli oggetti Ordine associati al cliente,
aggiunge i riferimenti a questi oggetti nella collezione dell'oggetto
Cliente, e restituisce la collezione
 È importante osservare che se il metodo non viene mai
invocato, il costo di caricare i dati relativi agli ordini non
viene mai pagato
 Se decidiamo di implementare questa strategia nella classe
Cliente mettiamo codice di gestione della persistenza in
una classe del dominio
 se in futuro vogliamo cambiare strategia?
 Per implementare bene la strategia Lazy Load senza
ridurre la coesione nella classe del modello è utile fare
riferimento al pattern Proxy
DAO, ORM e Hibernate
40
Lazy Load e classi proxy
 Le classi xxxDAOImpl non restituiscono un
bean “completo” ma un proxy
 Il proxy ha il compito di gestire il caricamento degli
oggetti collegati
 Il proxy deve contenere tutte le informazioni necessarie
per effettuare il caricamento “lazy”
 Gli oggetti collegati vengono caricati solo su richiesta
 Il proxy “simula” il comportamento del bean
DAO, ORM e Hibernate
41
Lazy Load: Dettagli
 Quando le classi xxxDAOImpl ricevono una richiesta viene
eseguita una query sul DB, istanziato e restituito un oggetto
del tipo richiesto
 L’oggetto istanziato non è di tipo xxxBean, ma xxxProxy
 La classe xxxProxy estende la corrispondente xxxBean e
riscrive i metodi che devono implementare le operazioni
onerose
 Vediamo un esempio…
DAO, ORM e Hibernate
42
Lazy Load: Implementazione con proxy
public class Cliente {
private int codiceCliente;
private List<Ordine> ordini;
…
public List<Ordine> getOrdini() {
return this.ordini;
}
...
}
public class ClienteProxy extends Cliente {
public List<Ordine> getOrdini() {
List<Ordine> listaOrdini = null;
try {
OrdineDAO daoOrdine = new OrdineDAOImpl();
listaOrdini = daoOrdine.doRetrieveByCliente(this.getCodice());
this.setOrdini(listaOrdini);
} catch (PersistenceException e) {
throw new UnChechedPersistenceException(e.getMessage());
}
return listaOrdini;
}
}
DAO, ORM e Hibernate
43
Lazy Load: Implementazione con proxy (e caching)
public class Cliente {
private int codiceCliente;
private List<Ordine> ordini;
…
public List<Ordine> getOrdini() {
return this.ordini;
}
...
}
public class ClienteProxy extends Cliente {
private boolean caricato = false;
public List<Ordine> getOrdini() {
try {
if (!this.caricato) {
OrdineDAO dao = new OrdineDAOImpl();
this.setOrdini(dao.doRetrieveByCliente(this.getCodice()));
this.caricato = true;
}
} catch (PersistenceException e) {
throw new UnChechedPersistenceException(e.getMessage());
}
return super.getOrdini();
}
}
DAO, ORM e Hibernate
44
Lazy Load: Osservazioni
 Quando uso il "caricamento pigro" ?
 Dipende dai casi d’uso definiti in fase di progettazione
 Ordine e RigaOrdine
 Esistono casi d’uso che prevedono l’uso dell’intestazione
dell’ordine ma non del dettaglio delle righe?
 RigaOrdine e Prodotto
 Esistono casi d’uso che prevedono l’uso di una o più riga
senza il dettaglio del prodotto?
 etc.
DAO, ORM e Hibernate
45
Lazy Load: Organizzazione del codice
 Organizzazione del codice:
 I Proxy appartengono al package della persistenza (in
particolare, al package con le implementazioni dei DAO)
DAO, ORM e Hibernate
46
Ricostruzione degli oggetti dal DB
 Concludiamo ora la scrittura del codice per la classe OrdineDAO
 In particolare supponiamo di voler effettuare un caricamento pigro del
cliente associato all'ordine
publicclass
classOrdineProxy
OrdineProxyextends
extendsOrdine
Ordine{ {
public
private Cliente
Cliente cliente;
cliente;
private
……
public
Cliente
getCliente()
throws
DAOException
{ {
public
Cliente
getCliente()
throws
DAOException
if
if (cliente==null)
(cliente==null) {{
String String
query =query
"select
* from *
clienti
" +
= "select
from clienti
" +
"where clienti.codice
=
?";
"where clienti.codice = ?";
……
}}
return
return cliente;
cliente;
} }
 C'è un problema: non abbiamo il codice cliente! Coerentemente con
l'approccio OO nella classe abbiamo un riferimento ad un oggetto
Cliente
 Questo dato è presente nella tabella ORDINI (chiave esterna), e
quando abbiamo caricato l'ordine questo valore non è stato salvato in
nessuna variabile!!
DAO, ORM e Hibernate
47
Ricostruzione degli oggetti dal DB
 Siamo costretti ad eseguire un join (ci sarebbe bastata una selezione)
publicclass
classOrdineProxy
OrdineProxyextends
extendsOrdine
Ordine{ {
public
private
Clientecliente;
cliente;
private
Cliente
… …
public
Cliente
getCliente()
{ {
public
Cliente
getCliente()
if
if (cliente==null)
(cliente==null) {{
String
String query
query == "select
"select ** from
from ordini
ordini join
join clienti
clienti on
on " +
ordini.id
=
clienti.idordine"
"ordini.idcliente = clienti.id where ordini.id = ?";
where ordini.id = ?";
//
// codice
codice per
per l'esecuzione
l'esecuzione della
della query
query
// con i dati ritornati viene costruito l'oggetto Cliente
// con i dati restituiti viene costruito l'obj Cliente
}…
return
cliente;
}
}
return cliente;
}
}
}
 Il problema sussiste anche nella classe Cliente? Perchè?
DAO, ORM e Hibernate
48
Ricostruzione degli oggetti dal DB
 Il problema sorge quando navighiamo una relationship
uno-a-molti o uno-a-uno seguendo il vincolo di integrità
referenziale (la chiave esterna)
 Per risolvere questo problema dobbiamo effettuare un
join (al posto di una semplice selezione)
DAO, ORM e Hibernate
49
Ricostruzione degli oggetti dal DB
 Possiamo sintetizzare il processo di ricostruzione degli
oggetti dal DB come segue:
 in base ai casi d'uso (e a una stima della frequenza delle
corrispondenti operazioni) decidiamo quando conviene
seguire una strategia Lazy Load
 per le classi con associazioni per le quali è stata scelta
la strategia Lazy Load applichiamo il pattern Proxy
 per le classi con associazioni per le quali non conviene
applicare la strategia Lazy Load ricostruiamo la rete
(parziale) di oggetti con i risultati di un join
 In fase di progettazione conviene quindi arricchire il class
diagram con annotazioni sulle associazioni che indicano la
strategia di caricamento ("fetch") dei dati: pigro (Lazy Load)
vs. immediato (Eager)
DAO, ORM e Hibernate
50
Caso di studio
Prodotto
CodiceProdotto
Nome
1
RigaOrdine
*
Quantità
Descrizione
Costo
Ordine
1
*
Data
NumeroLinea
fetch: lazy-load
CodiceOrdine
fetch: eager
stato
*
fetch: lazy-load
fetch: eager
1
Cliente
CodiceCliente
Nome
Indirizzo
DAO, ORM e Hibernate
51
Risolvere il conflitto di impedenza
 Nel modello OO, le relazioni tra oggetti sono realizzate con
riferimenti, mentre nel modello relazionale sono realizzate
con i valori
 Vediamo problemi e soluzioni relativamente a:
 Retrieve: dal DB agli oggetti
(ricostruzione degli oggetti a partire da dati persistenti)
 Create: dagli oggetti al DB
(memorizzazione persistente degli oggetti nel DB)
DAO, ORM e Hibernate
52
Create: Rendere persistenti gli oggetti
 L'operazione di CREATE ha lo scopo di rendere persistenti
gli oggetti della applicazione
 Problemi
 persistenza dei riferimenti
 propagazione degli aggiornamenti
DAO, ORM e Hibernate
53
Persistenza dei riferimenti
 Come rendiamo persistenti i riferimenti?
 se il dominio offre identificatori naturali per tutte le entità
il problema è limitato (ma potremmo fare considerazioni
su prestazioni e portabilità)
 se non tutte le classi hanno identificatori naturali
("semplici") è utile introdurre chiavi surrogate
 In generale è sconveniente usare un approccio ibrido
(chiavi surrogate e identificatori naturali)
 Di conseguenza, quando possibile*, è consigliato usare
sempre chiavi surrogate
 tutte le tabelle corrispondenti a entità del dominio hanno
una chiave id di tipo intero
 tutte le classi hanno una variabile di istanza id di tipo
intero
* Potrebbe non essere possibile nel caso di applicazioni costruite su DB già esistenti
DAO, ORM e Hibernate
54
Persistenza dei riferimenti
 Chiavi surrogate
 la chiave può essere vista come una rappresentazione
persistente dell'OID
 in parte cerchiamo di avvicinare i due mondi (relazionale
ed oggetti) senza stravolgerli, armonizzando le
differenze
 Questa soluzione offre vantaggi in termini di
 prestazioni (usando come chiavi degli interi)
 portabilità ed evoluzione (gli identificatori naturali
possono cambiare nel tempo*)
*Esempio: è allo studio una revisione del codice fiscale
DAO, ORM e Hibernate
55
Persistenza dei riferimenti
 Che cosa deve fare una operazione di Create
 se l'oggetto non esiste nel DB l'operazione di Create
deve eseguire una insert nel DB dei dati gestiti da un
oggetto del modello
 Se nel DB usiamo chiavi surrogate, come le gestiamo?
 è opportuno avere una rappresentazione della chiave
anche nel modello ad oggetti
 quindi ad ogni entità associamo esplicitamente una
variabile di istanza id (di tipo int)
DAO, ORM e Hibernate
56
Persistenza dei riferimenti
 Chi ci dà il valore di una chiave surrogata?
 la chiave viene creata al momento dell'inserimento di un
oggetto nel DB
 Diverse soluzioni:
 soluzione naive: chiedo al DB il valore massimo, lo
incremento ed eseguo l'inserimento usando tale valore
 uso campi auto-incrementanti: occorre aggiornare il
valore della variabile id nell'oggetto, ovvero dopo
l'inserimento, dobbiamo interrogare il DB per riottenere
tale valore
 uso una sequenza SQL che interrogo per farmi dare un
nuovo id prima di ogni inserimento
 efficiente (il DBMS offre anche funzionalità di caching)
 semplice da implementare
 qualche limite di portabilità (nonostante le sequenze siano
standard SQL, i vari DBMS differiscono un po' nell'uso di questo
costrutto)
DAO, ORM e Hibernate
57
Persistenza dei riferimenti
 Affidiamo la responsabilità della gestione degli id ad una
classe opportuna, che chiamiamo IdBroker
 Al solito, per favorire la portabilità possiamo definire una
interfaccia IdBroker, le cui implementazioni sono DBMSdependant
DAO, ORM e Hibernate
58
IdBroker: Esempio
package persistenza.db2;
import java.sql.*;
import persistenza.*;
public class IdBrokerDB2 implements IdBroker {
public int newId() throws PersistenceException {
int newId = -1;
DataSource ds = new DataSource();
ResultSet result = null;
PreparedStatement statement = null;
Connection connection = null;
try {
connection = ds.getConnection();
String sqlQuery = "SELECT(NEXTVAL FOR sequenza_id) INTO newId";
statement = connection.prepareStatement(sqlQuery);
result = statement.executeQuery();
if (result.next()) newId = result.getInt("newId");
else throw new PersistenceException("invalid id");
} catch(SQLException e) {
throw new PersistenceException(e.getMessage());
}
finally {
try {
if (statement != null) statement.close();
if (connection!= null) connection.close();
} catch (SQLException e) {
throw new PersistenceException(e.getMessage());
}
}
return newId;
}
}
DAO, ORM e Hibernate
59
Persistenza dei riferimenti: Esempio
public class ProdottoDAODB2 {
private void insert(Prodotto prodotto, Connection connection) throws
PersistenceException {
PreparedStatement statement = null;
IdBroker idBroker = new IdBrokerDB2();
try {
prodotto.setId(idBroker.newId());
String insert = "insert into prodotti(codice_prodotto, nome,
descrizione, disponibilita, prezzo, id) values
(?,?,?,?,?,?)";
statement = connection.prepareStatement(insert);
statement.setInt(1, prodotto.getCodiceProdotto());
statement.setString(2, prodotto.getNome());
statement.setString(3, prodotto.getDescrizione());
statement.setInt(4, prodotto.getDisponibilita());
statement.setInt(5, prodotto.getPrezzo());
statement.setInt(6, prodotto.getId());
statement.executeUpdate();
} catch (SQLException e) {
throw new PersistenceException(e.getMessage());
}
finally {
try {
if (statement != null) statement.close();
if (connection!= null) connection.close();
} catch (SQLException e) {
throw new PersistenceException(e.getMessage());
}
}
}
…
}
DAO, ORM e Hibernate
60
Sequenze SQL
 Statement SQL (DB2) per la creazione della sequenza:
CREATE SEQUENCE sequenza_id
AS INTEGER
START WITH 1
INCREMENT BY 1
MINVALUE 0
MAXVALUE 9999999
NO CYCLE;
DAO, ORM e Hibernate
61
Propagazione degli aggiornamenti
 Quando effettuiamo una operazione di create (ma
analogamente update o delete) propaghiamo gli
aggiornamenti a tutta la rete di oggetti ?
 Ad esempio, consideriamo la classe Ordine:
 quando salviamo i dati di un ordine, salviamo anche i
dati di tutti gli oggetti RigaOrdine e Cliente ad esso
associato?
 Anche in questo caso dipende dai casi d'uso
DAO, ORM e Hibernate
62
Progettazione della persistenza
 Facendo riferimento al class diagram, su tutte le
associazioni indichiamo:
 la cardinalità
 il verso secondo cui l'applicazione naviga la
associazione
 la strategia di fetch:
 Lazy Load vs. Eager (associata al verso)
 la strategia di propagazione degli aggiornamenti:
 Cascade vs. No cascade (associata al verso)
DAO, ORM e Hibernate
63
Caso di studio
Prodotto
CodiceProdotto
Nome
1
RigaOrdine
*
Quantità
Descrizione
Costo
Ordine
1
*
Data
NumeroLinea
fetch: lazy-load
cascade: none
CodiceOrdine
fetch: eager
cascade: persist, delete
stato
*
fetch: eager
cascade: none
fetch: lazy-load
cascade: none
1
Cliente
CodiceCliente
Nome
Indirizzo
DAO, ORM e Hibernate
64
Object Relational Mapping
 È tempo di riprendere e concludere il trattamento delle
metodologie alternative a “forza burta” e DAO per la
realizzazione del layer di persistenza, ovvero di trattare la
tecnica Object Relational Mapping (ORM, O/RM oppure
O/R mapping)
 Aumenta il livello di astrazione (semplicità di utilizzo per
lo sviluppatore e diminuzione della quantità di codice
che occorre scrivere) 
 Aumenta la complessità (diminuzione delle performance)

 ORM è “la persistenza automatica (e trasparente) di oggetti
di applicazioni Java in tabelle di un DB relazionale, basata
su metadati che descrivono il mapping tra oggetti e DB”
DAO, ORM e Hibernate
65
ORM in sintesi (1/3)
 Lavora trasformando (in modo reversibile) i dati da una
rappresentazione all’altra; ciò implica alcune penalizzazioni
in termini di performance
 tuttavia se ORM è implementato come “middleware”
esistono diverse opportunità di ottimizzazione non
possibili per un livello di persistenza “hand-coded ”
(à la JDBC)
 La fornitura e la gestione dei metadati che governano la
trasformazione aggiungono overead al tempo di sviluppo
 tuttavia tale costo è inferiore o equivalente al costo che
comporta il mantenimento di una soluzione
“hand-coded ”
DAO, ORM e Hibernate
66
ORM in sintesi (2/3)
 Una soluzione ORM consiste di quattro componenti:
 Una API per eseguire le operazioni CRUD sugli oggetti
delle classi del modello
 Un linguaggio o una API per specificare query che fanno
riferimento alle classi e alle proprietà delle classi
 Uno strumento per la specifica del mapping mediante
metadata
 Una tecnica per l’implementazione di ORM per interagire
con oggetti transazionali al fine di eseguire funzioni di
ottimizzazione quali, ad esempio, lazy load fetching e
dirty checking
DAO, ORM e Hibernate
67
ORM in sintesi (3/3)
 Usiamo il termine full ORM per includere ogni livello di
persistenza in cui SQL è automaticamente generato da una
descrizione basata su metadati
 L’applicazione interagisce con le API ORM e le classi del
modello di dominio ed astrae dal livello SQL/JDBC
sottostante
 Supporta object modeling sofisticati, quali composizione,
ereditarietà, polimorfismo e persistenza attraverso
raggiungibilità
 Un certo numero di tool commerciali e open source Java
ORM hanno raggiunto questo livello di qualità
 Hibernate è un tool full ORM
 l’API di Hibernate è nativa e progetta dagli sviluppatori
Hibernate
DAO, ORM e Hibernate
68
Perché ORM e Hibernate?
 Tra i benefici di ORM e Hibernate
 Produttività: il codice dedicato alla gestione della persistenza di una
applicazione Java è il più “tedioso”; Hibernate elimina la maggior
parte di questo duro lavoro permettendo di concentrare l’attenzione
su problemi di businnes logic
 Manutenibilità: poche linee di codice rendono il sistema più
comprensibile perché esso enfatizza aspetti di businnes logic
rispetto a dettagli implementativi; più importante, un sistema con
meno linee di codice è più facile per il refactor
 Performance: una comune affermazione è che la persistenza handcoded è sempre più performante rispetto a quella automatizzata;
occorre però considerare anche aspetti di tempo e budget per la
realizzazione della stessa
 Indipendenza dal vendor: ORM astrae una applicazione dal DB
sottostante e dal dialetto SQL; se un tool ORM supporta un certo
numero di DB (e la maggior parte lo fa) ciò conferisce portabilità alla
applicazioni
DAO, ORM e Hibernate
69
Perché Hibernate e non DAO?
 Per lo sviluppatore la metodologia DAO può risultare
onerosa (e “noiosa”), in termini di scrittura di codice, e
dipendente dal data source
 Inoltre persistenza e transazionalità sono gestite a
livello di programmazione
 La metodologia Hibernate rappresenta una soluzione
standard per riuscire a implementare persistenza e
transazionalità velocemente e senza preoccuparsi dei
dettagli del data source sottostante; esempio:
…
Session session = HibernateUtil.getSessionFactory().openSession();
User user = new User("pippo");
String userId = (String) session.save(user);
…
DAO, ORM e Hibernate
70
Il framework Hibernate
 Rappresenta lo standard risolutivo per il mapping
object/relational automatico tra oggetti Java e relazioni del
DB
 Tale mapping si può realizzare per mezzo di
 descrittori XML specifici di Hibernate (soluzione di
riferimento per noi)
 o, in alterantiva, di annotazioni Java conformi allo
standard JPA
 Il framework Hibernate si “appoggia” e sfrutta le tecnologie
SQL e JDBC
 ecco perché è stato coisì importante apprendere prima
JDBC! 
DAO, ORM e Hibernate
71
Un po’ di storia
 Il progetto relativo a Hibernate è stato promosso nel 2001
da Gavin King come alternativa all’uso di entity bean à la
EJB2
 scopo principale quello di offrire migliori capacità nella gestione
della persistenza semplificando tutte le complessità
 All’inizio del 2003, il gruppo di sviluppo Hibernate ha
avviato la realizzazione della release Hibernate 2 che offre
miglioramenti significativi rispetto alla prima versione
 Dal 2010 la versione di riferimento è Hibernate 3.x
 Hibernate 3 (dalla versione 3.5.0 in su) rappresenta
l’implementazione certificata (standard) delle specifiche
API Java Persistence, versione 2.0
 Ultima versione (febbraio 2016) Hibernate 5.1.0
DAO, ORM e Hibernate
72
Hibernate Core
 Anche noto come Hibernate o Hibernate 3.x
 Software open source e free, distribuito sotto licenza GNU
 Libreria ORM per Java: servizio di base per la gestione
della persistenza in applicazioni Java
 fornisce un framework per mappare un modello di
dominio object-oriented su di una base di dati
relazionale
 caratteristica primaria: mapping da classi Java a tabelle
di una base di dati (e mapping da tipi di dati Java a tipi di
dati SQL)
 inoltre, fornisce l’abilità di interrogare la basi di dati
DAO, ORM e Hibernate
73
Hibernate Core
 Il codice della applicazione usa le API di Hibernate per
gestire la persistenza
 I mapping tra classi Java e tabelle relazionali sono
specificati in appositi file XML
 In linea di principio, lo sviluppatore è esonerato da:
 richieste di esecuzione di chiamate SQL
 gestione manuale dei risultati di chiamate SQL e loro eventuale
conversione in oggetti
 L'applicazione rimane portabile in tutti i sistemi di gestione
supportati, con pochissimo overhead
 Può essere usato in maniera indipendente dal tipo di
applicazione, di piattaforma e di ambiente runtime,
con tutti i JDK
DAO, ORM e Hibernate
74
Architettura Hibernate
 L’architettura “completa” di Hibernate astrae dalle API
JDBC/JTA sottostanti
 livello di applicazione può essere trasparente a questi
dettagli
Architettura “completa”
Architettura di alto livello
DAO, ORM e Hibernate
75
Principali oggetti dell’API Hibernate*





SessionFactory
Session
Persistent Objects
Transient and Detached Object
Transaction
 N.B. Per ora ci basta pensare a una transazione come a una sequenza di
operazioni che può concludersi con un successo o un insuccesso (unità
atomica di elaborazione) ; affronteremo in modo approfondito la gestione
delle transazioni a breve…
 Connection Provider
 Transaction Factory
* http://docs.jboss.org/hibernate/core/3.5/api/
DAO, ORM e Hibernate
76
SessionFactory
 Classe org.hibernate.SessionFactory
 Factory per oggetti Session e cliente di ConnectionProvider
 Una factory per ogni DB
 Può mantenere una cache opzionale di secondo livello con
dati riusabili in diverse transazioni
DAO, ORM e Hibernate
77
Session
 Classe org.hibernate.Session
 Rappresenta un contesto di persistenza (wrapper a JDBC
Connection) e la sua vita è delimitata dall’inizio e dalla fine
di una transazione logica
 Gestisce le operazioni del ciclo di vita degli oggetti
persistenti
 Fa da factory per oggetti Transaction
 Mantiene una cache (non modificabile) di primo livello
derivante dal mapping con il DB che viene utilizzata
durante la navigazione degli oggetti
DAO, ORM e Hibernate
78
Oggetti persistent
 Oggetti single-threaded che contengono lo stato persistente
e la logica di business
 Possono essere normali JavaBean
 devono essere associati esattamente a un oggetto
Session
 Modifiche fatte sugli oggetti persistenti sono
automaticamente propagate sulle tabelle DB
(al
loro “commitment ”)
 Appena si chiude la sessione, gli stessi oggetti diventano
“detached” e possono essere usati liberamente
DAO, ORM e Hibernate
79
Oggetti transient e detached
 Istanze di classi persistenti che non sono correntemente
associati a nessuna Session
 Possono essere stati istanziati dalla applicazione e non
essere ancora diventati persistenti, oppure derivare da una
Session chiusa
 Modifiche fatte su questi oggetti non si riflettono sul DB
 Operazioni di persist o merge per farli tornare
“persistenti” (con modifiche correlate alle tabelle del DB)
DAO, ORM e Hibernate
80
Transaction
 Classe org.hibernate.Transaction
 Oggetto single-threaded usato dalla applicazione per
specificare unità atomiche di lavoro
 Permette di astrarre dai dettagli dei sottostanti meccanismi
transazionali (JDBC, JTA, …)
 Un oggetto Session può essere coinvolto in diverse
Transaction
 La demarcazione delle transazioni non è opzionale:
 indipendentemente dall’utilizzare le API JDBC sottostanti
o Transaction, deve comunque essere sempre
specificata in modo esplicito
DAO, ORM e Hibernate
81
ConnectionProvider
 Classe org.hibernate.connection.ConnectionProvider
 Factory per un pool di connessioni JDBC. Astrae la
applicazione dal Data Source o dal DriverManager
sottostante
 Non è esposta alla applicazione ma può essere estesa e/o
implementata dallo sviluppatore
DAO, ORM e Hibernate
82
TransactionFactory
 Classe org.hibernate.TransactionFactory
 Factory per oggetti Transaction
 Non è esposta alla applicazione ma può essere estesa e/o
implementata dallo sviluppatore
DAO, ORM e Hibernate
83
Stato degli oggetti persistenti
 Una istanza di una classe persistente può assumere in ogni
istante uno fra tre stati possibili, definiti all’interno di un
contesto di persistenza
 Transient
 non appartenente a un contesto di persistenza
 Persistent
 appartenente a un contesto di persistenza
 Detached
 usualmente appartenente a un contesto di persistenza ma
non in questo momento
DAO, ORM e Hibernate
84
Stato transient
 Istanza mai associata a una sessione (contesto di
persistenza)
 Non ha identità di persistenza (valore associato alla
primary key)
 Non ha righe corrispondenti nel DB
DAO, ORM e Hibernate
85
Stato persistent
 Istanza correntemente associata con una sessione
(contesto di persistenza)
 Ha una identità di persistenza (valore associato alla
primary key) e usualmente una riga corrispondente in una
tabella DB
 Ad es. quando un oggetto viene creato in una sessione
o un oggetto transient viene fatto diventare persistente
DAO, ORM e Hibernate
86
Stato detached
 Istanza che è stata associata a un contesto di persistenza
in passato, ma quella sessione è stata chiusa oppure
l’istanza è stata trasferita tramite serializzazione a un altro
processo
 Ha una identità di persistenza (valore associato alla
primary key) e possibilmente una riga corrispondente in
una tabella DB
 Ad es. quando un oggetto deve essere inviato ad un
altro processo, che lo utilizzerà senza necessità di avere
un contesto di persistenza associato
DAO, ORM e Hibernate
87
Il ciclo di vita degli oggetti persistenti
 Una applicazione orientata agli oggetti che fa uso di un meccanismo di
persistenza deve interagire con il servizio di persistenza ogni volta che
ha bisogno di propagare lo stato di un oggetto in memoria sulla base di
dati
 Lo stato di un oggetto che appartiene ad una classe persistente cambia
a seconda dell'operazione del servizio di persistenza che viene
invocata
DAO, ORM e Hibernate
88
Transizioni di stato
 Oggetti Transient possono diventare persistenti tramite
chiamate ai metodi save(), persist()o
saveOrUpdate(), ovviamente dell’oggetto Session
associato
 Ogni istanza di oggetto persistente restituita da get()o
load() è Persistent
 Oggetti Persistent possono diventare transienti tramite
l’invocazione di delete()
 Oggetti Persistent possono diventare “staccati” mediante
l’invocazione di evict(), clear()e close()
 Oggetti Detached possono diventare persistenti tramite
chiamate ai metodi update(), saveOrUpdate() e
merge()(con istanziazione di un nuovo oggetto
persistente)
DAO, ORM e Hibernate
89
Hibernate Query Language
 Hibernate fornisce un linguaggio di interrogazione ispirato a
SQL chiamato Hibernate Query Language (HQL)
 Permette la scrittura di query SQL-like definite sui data
object Hibernate; esempi:
Update a stock name to “DIALOG1″ where stock code is “7277″
Query query = session.createQuery("update Stock set stockName = :stockName" +
" where stockCode = :stockCode");
query.setParameter("stockName", "DIALOG1");
query.setParameter("stockCode", "7277");
int result = query.executeUpdate();
Delete a stock where stock code is “7277″
Query query = session.createQuery("delete Stock where stockCode = '7277'");
int result = query.executeUpdate();
 Sono inoltre supportate Criteria Queries come alternativa
Object Oriented a HQL
DAO, ORM e Hibernate
90
Hibernate: Strategie di fetching
 Una strategia di fetching determina come e quando i dati
vengono effettivamente caricati dal DB per una
applicazione che usa gli oggetti di persistenza associati
 La strategia adottata ha ovviamente impatto sulle performance
ottenibili ; di solito dichiarata in un file di mapping
 Modalità di fetching:
 FetchMode.DEFAULT (configurazione del mapping file)
 FetchMode.JOIN (Hibernate recupera i dati associati, anche
collezioni, utilizzando un join all’interno della stessa select)
 FetchMode.SELECT (Hibernate effettua una seconda select
separata per recuperare le entity o collection associate)
N.B. Il caricamento pigro (lazy fetching) è il default per SELECT: la
seconda select viene eseguita solo quando l’applicazione accede
veramente ai dati associati
DAO, ORM e Hibernate
91
Hibernate: Strategie di caching
 Utilizzato per motivi di performance
 Idea di base:
 Rendere l’accesso al DB necessario solo quando si
devono reperire dati non sono già disponibili sulla cache
 La applicazione può avere bisogno di svuotare
(invalidare) la cache se il DB viene aggiornato o se non
è possibile sapere se la cache mantiene ancora copie
aggiornate
 First-level cache
 Associata con l’oggetto Session
 Second-level cache
 Associata con l’oggetto SessionFactory
DAO, ORM e Hibernate
92
Hibernate: Strategie di caching
 Cache di primo livello: usata da Hibernate all’interno dei
confini di una singola transazione principalmente al fine di
ridurre il numero di query SQL generate all’interno di una
transazione
 Ad es. se un oggetto è modificato diverse volte
all’interno della medesima transazione, Hibernate
genera un unico statement SQL UPDATE alla fine della
transazione, con tutte le modifiche
 Cache di secondo livello: mantiene dati al livello di Session
Factory, utilizzabili da diverse transazioni (across
transaction boundaries)
 Oggetti persistenti disponibili per l’intera applicazione,
non solo per l’utente che sta eseguendo le query e per il
SessionBean associato
DAO, ORM e Hibernate
93
Hibernate in azione
 Cinque ingredienti principali di una applicazione che fa uso
di Hibernate per la gestione della persistenza:
 le classi di dominio realizzate in Java
 una base di dati (per noi realizzata in DB2)
 un file XML che definisce il mapping di ogni classe
persistente
 uno o più file di configurazione di Hibernate
 le interfacce Hibernate per l'accesso alla base di dati:
Session, Transaction e Query + package
org.hibernate
DAO, ORM e Hibernate
94
Classi di dominio e DB
 Sappiamo già come realizzarli dalle slide precedenti
 Esempio: classe “User” e relativa tabella “UTENTE”:
public class User {
private
private
private
private
private
private
String nome;
String cognome;
String username;
String password;
String email;
Indirizzo indirizzo;
public User(){}
public User(String user){
username=user;
}
CREATE TABLE UTENTE(
username VARCHAR(10) PRIMARY KEY,
nome VARCHAR(15),
cognome VARCHAR(15),
cod_fis VARCHAR(16) UNIQUE,
password VARCHAR(8),
email VARCHAR(20),
via VARCHAR(20),
civico INT,
cap VARCHAR(5),
citta VARCHAR(15));
…
}
DAO, ORM e Hibernate
95
File di mapping per le classi persistenti
 File XML che definisce come si mappano le proprietà delle
classi Java persistenti sulle tabelle del DB
 Deve soddisfare la grammatica specificata all'interno di un
apposito DTD chiamato
hibernate-mapping-3.0.dtd
N.B. Per verificare la correttezza sintattica del file XML,
Hibernate cercherà il DTD all'interno del classpath e lo
troverà nella libreria .jar di Hibernate (ammesso che il
classpath la includa)
 qualora non dovesse trovare il DTD, Hibernate lo
cercherà all'indirizzo specificato nella dichiarazione del
DOCTYPE
DAO, ORM e Hibernate
96
File di mapping per le classi persistenti: Esempio
File User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="User" table="UTENTE">
<id name="username" column="username"></id>
<property name="nome" column=“nome"></property>
<property name="cognome" column=“cognome"></property>
<property name="email"></property>
<property name="password"></property>
</class>
</hibernate-mapping>
DAO, ORM e Hibernate
97
File di mapping per le classi persistenti: Commenti
 L'elemento class dichiara il nome della classe persistente
e la tabella a cui essa corrisponde
 dice a Hibernate come rendere persistente e caricare gli
oggetti della classe User sfruttando la tabella UTENTE,
ovvero ogni istanza è rappresentata da una tupla della
tabella
 L'elemento id dichiara:
 il nome della proprietà della classe che gioca il ruolo di
identificatore
 Importante: una classe persistente è sempre caratterizzata
da una proprietà che ne identifica le istanze; una volta
creato un oggetto della classe, tale proprietà non potrà
essere modificata dalla applicazione
• il corrispondente metodo set può essere definito privato
DAO, ORM e Hibernate
98
File di mapping per le classi persistenti: Commenti
 il nome dell'attributo della tabella che identifica le tuple
mappate su oggetti (primary key)
 L'elemento property dichiara il nome delle proprietà
persistenti della classe e a quali attributi della tabella
corrispondono; di default, nessuna proprietà è persistente
 Importante: come per la proprietà che identifica gli
oggetti, il nome della proprietà indica ad Hibernate quali
metodi set e get usare
DAO, ORM e Hibernate
99
File di configurazione per Hibernate
 Hibernate costituisce la parte dell'applicazione che gestisce
la persistenza, ovvero che si connette al DB
 ha bisogno di avere le informazioni necessarie per
effettuare la connessione, quali il DBMS, il driver JDBC,
la base di dati, utente/password, etc.
 Un file XML fornisce tutte queste informazioni
 Tale file deve soddisfare la grammatica specificata
nel DTD hibernate-configuration-3.0.dtd
DAO, ORM e Hibernate
100
File di configurazione per Hibernate: Esempio
File hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">
com.ibm.db2.jcc.DB2Driver</property>
<property name="hibernate.connection.url">
jdbc:db2://diva:deis.unibo.it:50000/tw_stud</property>
<property name="connection.username">*****</property>
<property name="connection.password">*****</property>
DAO, ORM e Hibernate
101
File di configurazione per Hibernate: Esempio
<!-- SQL dialect -->
<property name="dialect">
org.hibernate.dialect.DB2Dialect</property>
<!-- JDBC connection pool (use C3P0) -->
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">20</property>
<property name="c3p0.timeout">300</property>
<property name="c3p0.max_statement">50</property>
<!-- Show and print nice SQL on stdout -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- List of XML mapping files -->
<mapping resource="User.hbm.xml" />
</session-factory>
</hibernate-configuration>
DAO, ORM e Hibernate
102
File di configurazione per Hibernate: Commenti
 L'elemento session-factory definisce le impostazioni
per l'accesso a un particolare DB
 Le proprietà il cui nome hanno la forma
(hibernate).connection.* contengono le
informazioni necessarie per impostare la connessione
JDBC
 La proprietà dialect specifica la variante di SQL che
deve generare Hibernate
DAO, ORM e Hibernate
103
File di configurazione per Hibernate: Commenti
 Le proprieta c3p0.* indicano le impostazioni necessarie
a configurare il software c3p0 per il pooling di connessioni
 min size: numero minimo di connessioni che devono
essere pronte in ogni momento
 max size: numero massimo di connessioni aperte
gestite dal pool
 timeout: tempo al termine del quale una connessione
aperta non più usata viene rimossa
 max statements: numero di prepared statements
che sono mantenuti in cache
 Infine mapping include l’elenco dei file di mapping XML
DAO, ORM e Hibernate
104
Le interfacce Hibernate
 Tre sono le interfacce principali per l'accesso al DB, tutte
appartenenti al package org.hibernate
 Session: ogni istanza rappresenta una sessione di
comunicazione tra applicazione e base di dati
 comprende i metodi per salvare/caricare oggetti
nella/dalla base di dati
 Transaction: ogni istanza rappresenta una transazione
 maggiore disaccoppiamento dell'applicazione: non è
necessario usare l'API JDBC per impostare una
transazione
DAO, ORM e Hibernate
105
Le interfacce Hibernate
 Gioca il ruolo di gestore di transazioni in un sistema che
accede a più DB all'interno di una unica unità di lavoro di
sistema
 Query: interfaccia che permette di creare ed eseguire query
 sia nel linguaggio di query di Hibernate (HQL) che in
SQL
 che usino al loro interno delle variabili
(:nomeVaraibile)
DAO, ORM e Hibernate
106
Interfacce Hibernate: Esempio d'uso
File Bid.java
package bid;
import java.util.*;
import org.hibernate.*;
import persistence.HibernateUtil;
public class Bid {
public static void main(String[] args) {
//First unit of work
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
User user = new User("pippo");
String userId = (String) session.save(user);
tx.commit();
session.close();
DAO, ORM e Hibernate
107
Interfacce Hibernate: Esempio d'uso
//Second unit of work
session = HibernateUtil.getSessionFactory().openSession();
tx = session.beginTransaction();
user = (User) session.get(User.class,userId);
user.setNome("Filippo");
tx.commit();
session.close();
//Third unit of work
session = HibernateUtil.getSessionFactory().openSession();
tx = session.beginTransaction()
List users = session.createSQLQuery("select * from UTENTE
order by username").addEntity(User.class).list();
System.out.println(users.size()+" user(s) found: ");
for (Iterator iter= users.iterator(); iter.hasNext(); ) {
User userId = (User) iter.next();
System.out.println (userId.getNome()); }
tx.commit();
session.close();
HibernateUtil.shutdown(); //Shutting down the application
} }
DAO, ORM e Hibernate
108
Interfacce Hibernate: Commenti
 L'utilizzo della interfaccia Transaction imposta
l'autocommit a false
 necessità di chiamare il metodo commit
 Tutti i comandi SQL sono generati a runtime
 La prima unità di lavoro, quando eseguita, corrisponde ad
effettuare sul DB un comando SQL simile a:
insert into UTENTE (USERNAME,NOME,COGNOME,
COD_FIS,PASSWORD,EMAIL,VIA,CIVICO,CAP,CITTA)
values (’pippo’, null, null, null, null, null, null,
null, null, null);
DAO, ORM e Hibernate
109
Interfacce Hibernate: Commenti
 La seconda unità di lavoro mostra l'abilita di:
 caricare un oggetto dalla base di dati, a partire dalla
classe di cui è istanza e dal suo identificatore
 il metodo get(Class,Serializable) restituisce una
istanza della classe persistente data in input caratterizzata
dall'identificatore in input, e null se la suddetta istanza non
esiste
 effettuare un dirty checking automatico: senza che sia
richiesto esplicitamente di fare l'update dell'istanza,
Hibernate si accorge delle modiche apportate sulla
proprietà nome ed aggiorna automaticamente la base di
dati
DAO, ORM e Hibernate
110
Interfacce Hibernate: Commenti
 La terza unita di lavoro mostra come è possibile
incapsulare una query di accesso al DB e ricavare dai
risultati oggetti del dominio
 questo tipo di accesso deve essere limitato a quei casi in
cui è necessario effettuare una ricerca sul DB non di tipo
diretto, ad esempio, FindByCriteria
DAO, ORM e Hibernate
111
Inizializzazione di Hibernate: SessionFactory
 Per inizializzare Hibernate, si costruisce un oggetto
SessionFactory a partire da un oggetto Configuration
 Un oggetto Configuration, sostanzialmente, rappresenta il
file di configurazione di Hibernate SessionFactory
sessionFactory = new
Configuration().configure().buildSessionFactory();
 quando new Configuration()è invocato, Hibernate
cerca un file chiamato hibernate.properties e
tutte le impostazioni definite sono associate all'oggetto di
Configuration
 quando configure()è invocato, Hibernate cerca il file
hibernate.cfg.xml
DAO, ORM e Hibernate
112
Inizializzazione di Hibernate: SessionFactory
 Nella maggior parte delle applicazioni, SessionFactory
deve essere istanziato una sola volta durante la fase di
inizializzazione di Hibernate, e gioca il ruolo di gestore delle
sessioni, nel senso che ogni istanza di Session deve
essere creata a partire da lui
 è buona prassi realizzare una classe HibernateUtil per
l'inizializzazione di Hibernate e la gestione della singola
istanza di SessionFactory
DAO, ORM e Hibernate
113
Gestore delle sessioni: HibernateUtil
File HibernateUtil.java
package persistence;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class HibernateUtil {
private static SessionFactory sessionFactory = initHibernateUtil();
private static SessionFactory initHibernateUtil(){
try {
return new Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) {
throw new ExceptionInInitializerError(ex); }
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close(); //Close caches and connection pools
} }
DAO, ORM e Hibernate
114
Mappare una classe Java significa...
 Stabilire una corrispondenza tra le sue istanze e le tuple
della tabella corrispondente
 Mappare il suo identificatore
 Mappare le sue proprietà persistenti
 proprietà che sono valori
 proprietà che sono istanze di una altra classe di dominio
Java
DAO, ORM e Hibernate
115
Mappare gli identificatori delle classi di dominio
 Dal punto di vista sintattico, una proprietà che identifica una
classe deve essere mappata attraverso l'elemento XML
<id> (che deve essere definito)
 <id> può avere un elemento figlio <generator> che
deve avere un attributo class che specifica una classe
Java che implementa l'interfaccia
org.hibernate.id.IdentifierGenerator e che
viene usata per generare identificatori unici ; Hibernate
viene fornito con delle classi built-in per generare
identificatori, tra le altre:
 assigned: significa che l'applicazione assegna l'identificatore
all'istanza prima che sia chiamato il metodo save - questo è il
comportamento di default se generator non compare
 native: usa i generatori di identificatori forniti dal DBMS
sottostante; mantiene il mapping portabile
DAO, ORM e Hibernate
116
Mappare proprietà delle classi di dominio
 Abbiamo già visto come mappare una proprietà persistente
di una classe quando la stessa corrisponde a un valore con
molteplicità massima pari a uno
 mediante l’uso dell'elemento XML property
 Quando invece una proprietà è una collezione omogenea di
valori gestiti da una altra tabella , allora nel file di mapping
si definisce un elemento apposito, quale Set, List, ecc.
 Si rimanda alla documentazione e al materiale
dell’esercitazione guidata in laboratorio per dettagli
 Diciamo qualcosa in più sul sistema di tipi di Hibernate…
DAO, ORM e Hibernate
117
Il sistema di tipi di Hibernate
 I tipi Hibernate sono di fatto dei convertitori che traducono
da tipi Java a tipi SQL e viceversa
 La maggior parte dei tipi built-in di Hibernate hanno lo
stesso nome del tipo Java che mappano
 Possono però esserci più tipi Hibernate per uno stesso
tipo Java
 bisogna allora indicare nel file di mapping il tipo di
mapping che Hibernate deve usare
DAO, ORM e Hibernate
118
Tipi primitivi di Hibernate: Corrispondenze SQL-Java
DAO, ORM e Hibernate
119
Tipi di dati Hibernate sulle date e il tempo
DAO, ORM e Hibernate
120
Come usare i tipi di Hibernate nei mapping: Esempio
<class name="Item" table="ITEM">
(...)
<property name="giornoInizio" type="time"
column="INIZIO"/>
</class>
 N.B. Se non specifichiamo il tipo di Hibernate, allora
Hibernate usa la reflection, ovvero risale al tipo Java della
proprietà giornoInizio della classe Item e assume un
comportamento di default
 se abbiamo definito la proprietà giornoInizio di tipo
java.util.Date, Hibernate cerca di convertirla nel
tipo TIMESTAMP (diverso da TIME)
DAO, ORM e Hibernate
121
Riferimenti
 DAO:
 http://java.sun.com/blueprints/corej2eepatterns/
Patterns/DataAccessObject.html
 ORM:
 http://www.agiledata.org/essays/mappingObjects.html
 Hibernate:
 http://www.hibernate.org/
 http://www.visualbuilder.com/java/hibernate/
tutorial/
 http://docs.jboss.org/hibernate/stable/core/
reference/en/html/
 API: http://docs.jboss.org/hibernate/core/3.5/api/
 Helen Feddema. “DAO Object Model: The Definitive Reference”,
O'Reilly Media
 Christian Bauer and Gavin King. “Java Persistence with
Hibernate”, Manning
DAO, ORM e Hibernate
122

Documenti analoghi

5 Hibernate3 Configurazione

5 Hibernate3 Configurazione Hibernate ci suggerisce di costruire una classe di utilità per la gestione della SessionFactory. Tale classe prende il nome di HibernateUtil.

Dettagli

Guida Introduttiva ad Hibernate

Guida Introduttiva ad Hibernate tipi SQL), ma fornisce anche degli aiuti per le query di dati, il recupero di informazioni e riduce significativamente il tempo che altrimenti sarebbe speso lavorando manualmente in SQL e con JDBC....

Dettagli

Programmazione Java Avanzata

Programmazione Java Avanzata Hibernate permette di scrivere codice che si riferisce agli oggetti Java, automatizzando le operazioni CRUD, tramite la generazione automatica del codice SQL che lega gli oggetti alle tabelle del D...

Dettagli

Documentazione di Riferimento

Documentazione di Riferimento 6.2. Come mappare una collezione ........................................................................................... 48 6.3. Collezioni di valori e associazioni molti-a-molti .................

Dettagli