Versione preliminare Antonella Poggi Dipartimento di informatica e Sistemistica Sapienza Universit` di Roma a Progetto di Applicazioni Software Anno accademico 2008-2009
Riferimenti bibliograci
Libro Java Persistence with Hibernate, Christian Bauer and Gavin King - Editore: Manning Hibernate Reference Documentation (cf. link sulla pagina web del corso)
A. Poggi
Argomenti principali
Introduzione ad Hibernate e suoi principali utilizzi Le basi della gestione della persistenza con Hibernate Mapping pi` complessi u Le transazioni e il ciclo di vita degli oggetti Creare un livello generico per la gestione della persistenza
A. Poggi
A. Poggi
Hibernate core
Anche noto come Hibernate o Hibernate 3.3.x Software open source e free, distribuito sotto licenza GNU ORM libreria 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 database 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) + abilit` di interrogare la basi di dati a
A. Poggi 4
Il codice dellapplicazione usa le API di Hibernate per gestire la persistenza I mapping tra classi Java e tabelle relazionali sono specicati in appositi le XML in linea di principio, lo sviluppatore ` esonerato da: e
richieste di esecuzione di chiamate SQL gestione manuale dei risultati di chiamate SQL e loro eventuale conversione in oggetti
Lapplicazione rimane portabile in tutti i sistemi di gestione supportati, con pochissimo overhead Pu` essere usato in maniera independente dal tipo di o applicazione, di piattaforma e di ambiente runtime, con tutti i JDK
A. Poggi
Hibernate tools
Insieme di strumenti per Hibernate 3 Forniscono dei task Ant e dei plugin Eclipse per fare reverse engineering, generazione di codice, e, pi` in u generale, per interagire con Hibernate
Ant: strumento per fare il build, la compilazione e il deployment di applicazioni Java complesse Eclipse: ambiente di sviluppo open-source, molto essibile
A. Poggi
A. Poggi
metadati ottenuti dal catalogo e genera il le di congurazione di Hibernate (cf. slides pi` avanti) u
Problemi:
lo schema della base di dati deriva, nella migliore delle ipotesi, da un degrado dello schema ER non si potr` mai ottenere un diagramma delle a classi che sfrutti caratteristiche importanti della programmazione ad oggetti, e.g. ereditariet`, a polimorsmo la logica dellapplicazione ` inuenzata dalla e rappresentazione dei dati il diagramma delle classi di dominio conterr` solamente le classi persistenti a
A. Poggi
10
A. Poggi
12
Hibernate in azione
5 principali ingredienti di unapplicazione che fa uso di Hibernate per la gestione della persistenza
le classi di dominio realizzate in Java una base di dati, e.g. realizzata in Mysql un le che denisce il mapping di ogni classe persistente uno o pi` le di congurazione di Hibernate u le interfacce Hibernate per laccesso alla base di dati: Session, Transaction e Query - package org.hibernate
A. Poggi
13
Le classi di dominio
Le classi di dominio sono denite come in qualsiasi applicazione Java tipicamente, metodi set e get per laccesso in scrittura e lettura delle propriet` degli oggetti della a classe metodi di business della classe
A. Poggi
14
vincente
Offerta
ammontare : int dataCreazione: Date
0..* fattaDa
Item
nome : String codice : int descrizione : String prezzoIniziale: int giornoInizio: Date giornoFine: Date calcolaTempoResiduo(): int
User
nome : String cognome : String username: String password: String email: String calcolaCostoSpedi zione(): int
Indirizzo
risiede
via : String civico : int cap: String citt: String
0..*
compratoDa
A. Poggi
15
A. Poggi
16
public String getNome() { return nome;} public void setNome(String nome) { this.nome=nome;} public String getCognome() { return cognome;} public void setCognome(String cognome) { this.cognome=cognome;} public String getUsername() { return username;} public void setUsername(String username) { this.username=username;} public String getPassword() { return password;} public void setPassword(String password) { this.password=password;} public String getEmail() { return email;} public void setEmail(String email) { this.email=email;}
public Indirizzo getIndirizzo() { return indirizzo;} public void setIndirizzo(Indirizzo indirizzo) { this.indirizzo=indirizzo public int calcolaCostoSpedizione {
A. Poggi
17
A. Poggi
18
A. Poggi
19
La base di dati
` E costituita da un insieme di: tabelle vincoli store procedure, trigger ` E mantenuta allinterno di un certo DBMS, e.g. Mysql, provvisto del proprio driver jdbc
A. Poggi
20
A. Poggi
21
A. Poggi
23
una classe persistente ` sempre caratterizzata da e una propriet` che ne identica le istanze a una volta creato un oggetto della classe, tale
A. Poggi 24
propriet` non potr` essere modicata a a dallapplicazione (il corrispondente metodo set pu` essere denito privato) o il nome dellattributo della tabella che identica le tuple mappate su oggetti
Lelemento property dichiara il nome delle propriet` a persistenti della classe e a quali attributi della tabella corrispondono; di default, nessuna propriet` ` a e persistente Importante: come per la propriet` che identica gli a oggetti, il nome della propriet` indica ad Hibernate a quali metodi set e get usare
A. Poggi
25
WORKDIR + lib <Hibernate ed altre librerie> + src + bid User.java User.hbm.xml + bin
A. Poggi
26
A. Poggi
27
A. Poggi
28
<property name="dialect"> org.hibernate.dialect.MySQL5InnoDBDialect</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="bid/User.hbm.xml" /> </session-factory> </hibernate-configuration>
A. Poggi
29
min size: numero minimo di connessioni che deono 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 u max statements: numero di prepared statements che sono mentenuti in cache
A. Poggi
31
WORKDIR + lib <Hibernate ed altre librerie> + src + bid User.java User.hbm.xml hibernate.cfg.xml + bin
A. Poggi
32
Le interfacce Hibernate
Hibernate fornisce tre principali interfacce per laccesso alla base di dati, 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 dellapplicazione: non ` e necessario usare lAPI JDBC per impostare una transazione gioca al ruolo di gestore di transazioni in un sistema che accede a pi` basi di dati allinterno di ununica u unit` di lavoro di sistema a
A. Poggi 33
utile in tutti quei casi in cui era necessario ricorre ad un DCS nellapproccio DAO
A. Poggi
34
A. Poggi
35
//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();
A. Poggi
36
A. Poggi
37
La terza unit` di lavoro mostra come ` possibile a e incapsulare una query di accesso alla base di dati e ricavare dai risultati oggetti del dominio questo tipo di accesso deve essere limitato a quei casi in cui si usano i DCS nellapproccio DAO, ovvero, essenzialmente, ai casi in cui ` necessario eettuare una e ricerca sulla base di dati non di tipo diretto, e.g. FindByCriteria
A. Poggi
40
quando configure() ` chiamato, Hibernate cerca il e le hibernate.cfg.xml la locazione in cui Hibernate cerca i le suddetti ` e quella specicata nel classpath se si vuole usare unaltra locazione la si deve specicare in input esistono altre maniere di impostare delle propriet` a della connessione (cf. documentazione)
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 e per linizializzazione di Hibernate e la gestione della singola istanza di SessionFactory
A. Poggi 42
A. Poggi
43
public static SessionFactory getSessionFactory() { return sessionFactory; } public static void shutdown() { //Close caches and connection pools getSessionFactory().close(); } }
A. Poggi
44
WORKDIR + lib <Hibernate ed altre librerie> + src +bid User.java User.hbm.xml Bid.java + persistence HibernateUtil.java hibernate.cfg.xml + bin
A. Poggi 45
I mapping
A. Poggi
46
In poche parole...
come le classi Java che realizzano classi di dominio UML persistenti siano mappate sugli elementi della base di dati informazioni sugli elementi stessi della base di dati che vengono mappati queste sono utili nellapproccio top-down, ovvero quando a partire dalle classi di dominio e dai mapping si intende generare la base di dati sottostante - in questo corso non approfondiremo questo argomento
A. Poggi
47
Note importanti
1. In questa trattazione, assumeremo che la porzione persistente del diagramma delle classi e lo schema ER siano simili, nel senso che:
la realizzazione di una classe di dominio persistente ` mappata su una ed ununica tabella e le realizzazioni di due classi di dominio persistenti in ISA sono mappate su due tabelle legate da una foreign key le realizzazioni di due classi di dominio persistenti legate da unassociazione sono mappate su due tabelle legate da una o pi` catene di vincoli di u foreign key/inclusione (che eventualmente coinvolgono ulteriori tabelle)
A. Poggi 48
Per tutti i casi di mapping che non rientrano tra i tipi di cui sopra, Hibernate fornisce delle soluzioni non soddisfacibili ` pertanto necessario ricorrere allapproccio DAO e
A. Poggi
49
2. la realizzazione in java del diagramma delle classi di dominio segue le regole viste nel corso di Progettazione del Software, con le seguenti principali eccezioni, riguardanti i campi privati persistenti che sono collezioni:
si denisce il metodo set come per gli altri tipi di campi - ma attenzione: lo si denisce private permette ad Hibernate, ma non al client, di usarlo il metodo get non restituisce un clone della collezione, bens` la collezione stessa (restrizione di Hibernate)
A. Poggi
50
A. Poggi
51
non pu` essere modicata una volta che ` stata o e assegnata ad unistanza dal punto di vista sintattico, una propriet` che a identica una classe deve essere mappata attraverso lelemento XML <id> (che DEVE essere denito)
A. Poggi
52
<id> pu` avere un elemento glio <generator> che o DEVE un attributo class che specica una classe Java che implementa linterfaccia org.hibernate.id.IdentifierGenerator e che viene usata per generare identicatori unici; se tale classe prende dei parametri in ingresso, vengono specicati per mezzo di elementi gli param; Hibernate viene fornito con delle classi built-in per generare identicatori, tra le altre:
assigned signica che lapplicazione assegna lidenticatore allistanza prima che sia chiamato il metodo save - questo ` il comportamento di default se e generator non compare native: usa i generatori di identicatori forniti dal DBMS sottostante - mantiene il mapping portabile
A. Poggi
53
A. Poggi
54
Tipo Java
int or java.lang.Integer long or java.lang.Long short or java.lang.Integer float or java.lang.Float double or java.lang.Double java.math.BigDecimal java.lang.String java.lang.String float or java.lang.Float boolean or java.lang.Boolean
A. Poggi
56
Tipo Java
java.util.Date or java.sql.Date java.util.Time or java.sql.Time java.util.Timestamp
or java.sql.Timestamp
calendar calendar_date TIMESTAMP DATE java.util.Calendar java.util.Calendar
A. Poggi
57
Per le classi che realizzano un nuovo tipo UML, ` e necessario ridenire i metodi toString, equals(), hashCode() e, se qualche funzione della classe Java eettua side-eect, clone()
A. Poggi 59
Ipotesi: come sempre, le colonne da mappare appartengono alla stessa tabella su cui ` mappata la classe e A seconda che sia o no necessario eettuare una conversione od una forma di type checking tra i valori delle propriet` della classe che realizza il tipo UML, ed il valore a degli attributi della base di dati mappati, si usa un diverso approccio
A. Poggi
60
Lelemento XML component serve per mappare le propriet` a di una classe Java denita dallutente che:
non ` una classe di dominio e deve essere resa persistente nella stessa tabella sulla quale si denisce il mapping per la classe per la quale denisce il mapping lelemento padre dellelemento component (N.B. si pu` anche fare un uso annidato o dellelemento component) component pu` essere usato quando non si ha bisogno di o eettuare alcuna conversione di tipo
A. Poggi
61
A. Poggi
62
public void setCap(String cap) { this.cap=cap;} public int getNumeroCivico() { return numeroCivico;} public void setNumeroCivico(int numero) { this.numeroCivico=numero;} public String getCitta() { return citta;} public void setCitta(String citta) { this.citta=citta;} }
A. Poggi
63
A. Poggi
64
Hibernate permette di denire dei tipi Hibernate ad-hoc nei casi in cui i tipi built-in non siano adeguati
sono fornite diverse interfacce pi` o meno complesse a u seconda del tipo di conversione da eettuare ` necessario denire una classe Java che implementa e una delle interfacce e che eettua la conversione da/verso valori della classe Java che realizza il tipo verso/da valori nella base di dati linterfaccia pi` comunemente usata ` u e org.hibernate.usertype.UserType: fornisce i metodi di base per eettuare il caricamento ed il salvataggio di istanze di classi che realizzano tipi di dato
A. Poggi 65
unaltra interfaccia ` e org.hibernate.usertype.CompositeUserType: fornisce inoltre metodi per esporre/modicare propriet` a interne di istanze di classi che realizzano tipi UML non rientra negli scopi del corso
A. Poggi
66
Supponiamo che per le propriet` giornoInizio e a giornoFine della classe di dominio Item, si decida di evitare luso del tipo java.sql.Date e si voglia piuttosto usare il tipo GregorianCalendar si deve denire una classe che eettua la conversione dal tipo sql DATE degli attributi inizio e fine della tabella ITEM al tipo GregorianCalendar
A. Poggi
67
Nel le di mapping Item.hbm.xml si denisce come mappare le propriet` si cui sopra come segue: a
<hibernate-mapping> <class name="bid.Item" table="ITEM"> (...) <property name="giornoInizio" column="inizio" type="persistence.GregorianCalendarUserType"/> <property name="giornoFine" column="fine" type="persistence.GregorianCalendarUserType"/> </class> </hibernate-mapping>
A. Poggi
68
A. Poggi
69
//indica ad Hibernate i tipi SQL da mappare - possono essere pi` di uno u public int[] sqlTypes(){ return new int[] {Hibernate.DATE.sqlType()}; } //indica ad Hibernate il tipo Java da mappare public Class returnedClass() { return GregorianCalendar.class; } //indica se il tipo Java ` immutabile e //utile per effettuare eventuali ottimizzazioni public boolean isMutable() { return false; } //per eseguire il dirty checking, il tipo Hibernate usa i seguenti //metodi, che tipicamente delegano ai metodi corrispondenti del tipo Jav public boolean equals(Object x, Object y) throws HibernateException { if (x==y) return true; if (x==null || y==null) return false; return x.equals(y);
A. Poggi
70
} public int hashCode(Object x) throws HibernateException { return x.hashCode(); } //restituisce una copia del valore del tipo Java - se il tipo //` immutabile, ` sufficiente restituire il riferimento alloggetto e e public Object deepCopy(Object value) throws HibernateException { if (value==null) return value; else { GregorianCalendar g= (GregorianCalendar) ((GregorianCalendar) value).clone(); return g; } } //metodo che converte e restituisce i valori ottenuti dal JDBC //ResultSet nel valore della propriet` Java corrispondente a public Object nullSafeGet(ResultSet resultSet, String[] names, Object ow throws HibernateException,SQLException { String s = resultSet.getDate(names[0]).toString(); int year=Integer.parseInt(s.substring(0,4));
A. Poggi
71
int month=Integer.parseInt(s.substring(5,7)); int day=Integer.parseInt(s.substring(8,10)); return new GregorianCalendar(year,month,day); } //metodo che converte e scrive il valore della propriet` Java del a //tipo sul JDBC PreparedStatement che esegue il salvataggio public void nullSafeSet(PreparedStatement statement, Object value, int i throws HibernateException, SQLException { if (value==null){ statement.setNull(index,Hibernate.DATE.sqlType()); } else { GregorianCalendar g= (GregorianCalendar) value; String s = g.get(Calendar.YEAR)+"-"+g.get(Calendar.MONTH)+"-"+ g.get(Calendar.DAY_OF_MONTH); statement.setDate(index,java.sql.Date.valueOf(s)); } } //metodo chiamato per effettuare il merge di ogetti in stato //"detached" - cf. lezione pi` avanti - se il tipo u //` immutabile, ` sufficiente restituire il riferimento alloggetto e e
A. Poggi
72
public Object replace(Object original, Object target, Object owner) throws HibernateException { return deepCopy(original); } //metodi chiamati per usare il secondo livello di cache //in questo corso ignoriamo il secondo livello di cache, pertanto //questi metodi saranno sempre definiti come segue public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached; } public Serializable disassemble(Object value) throws HibernateException { return (Serializable) value; } }
A. Poggi
73
A. Poggi
74
IDD ` lattributo di TABP che identica listanza di D per e la quale si denisce il mapping ColumnP ` la colonna di TABP che contiene i valori della e collezione mappati
A. Poggi
75
<list name="P" table="TABP"> <key column="IDD"/> <list-index column="POSITION"/> <element type="TypeP" column="ColumnP"/> </list>
dove POSITION ` lattributo di TABP che contiene il valore e dellindice della lista
A. Poggi
76
propriet` riferimento ad unistanza di unaltra classe a persistente propriet` insieme di riferimenti ad istanze di unaltra a classe propriet` riferimento ad unistanza di una classe a TipoLink propriet` insieme di riferimenti ad istanze di una classe a TipoLink
A. Poggi
77
A. Poggi
78
Ci sono 2 casi:
Caso 1: TabA ha accorpato la relazione ER corrispondente a R in TabA sar` denito un vincolo di foreign key verso a TabB
Si usa lelemento one-to-one:
A. Poggi
79
Caso 2: la relazione ER corrispondente a R ha portato ad una tabella T abR T abR ha due foreign key FKA, FKB verso le tabelle su cui sono mappate A e B , rispettivamente
Si usa lelemento join:
A. Poggi
80
A. Poggi
81
Caso 1: TabB ha accorpato la relazione ER corrispondente a R in TabB ` denita una foreign key FKA verso TabA e
Si usa lelemento set:
Caso 2: la relazione ER corrispondente a R ha portato ad una tabella T ABR T abR ha due foreign key FKA, FKB verso le tabelle su cui sono mappate A e B , rispettivamente
Si usa anche questa volta lelemento join:
<join table="TabR" optional="true"> <key column="FKA"/> <many-to-one name="PropB" class="B" column="FKB"/> </join>
A. Poggi
83
Cascading di oggetti
Quando una classe A ha responsabilit` su di unassociazione a AB con B , Hibernate fornisce la possibilit` di richiedere che a una qualsiasi operazione di persistenza su A sia transitiva es. il salvataggio di un oggetto di A, implichi il salvataggio delloggetto di B associato ad A Si denisce uguale ad "all" lattributo cascade dellelemento XML che denisce il mapping per lassociazione per indicare ad Hibernate che tutte le operazioni devono essere persistenti (altrimenti si usa il nome delloperazione, e.g. "save-update") Attenzione: Nel caso del delete transitivo, bisogna fare attenzione a non lasciare dei riferimenti ad oggetti appesi (cf. corso di Progettazione del software)
A. Poggi 84
R ha un attributo e/o A e B hanno entrambe responsabilit` su R a la realizzazione in Java porta ad una classe java T ipoLinkAB che realizza il link tra le istanze di A e B , ed ad una classe java che realizza A e ha ad una propriet` P ropB a che ` un riferimento ad unistanza della classe T ipoLinkAB e Idea: mappiamo anche la classe T ipoLinkAB con laccortezza di usare un identicatore composto sia dallidenticatore di A che dallidenticatore B
A. Poggi 85
Quando si mappa pi` volte lo stesso link tra oggetti di u classi java, il mapping indica a Hibernate di eettuare la stessa operazione di persistenza pi` volte u si possono ottenere delle violazioni di chiave! Si sceglie un verso per il link, e si denisce uguale a "true" lattributo inverse del mapping che specica come mappare il link nellaltro verso. Esempio: caso delle classi TipoLink
A. Poggi
86
Mappare gerarchie
Supponiamo di avere una generalizzazione completa, tale che due classi A e B specializzano G, rispettivamente mappate sulle tabelle TabA, TabB e TabG, tali che TabA e TabB abbiano entrambe una foreign key FKA e FKB verso TabG Si denisce il mapping per G, denendo come mappare, oltre alle propriet` di G, anche le propriet` delle sue a a sottoclassi A e B .
A. Poggi
87
A. Poggi
88
A. Poggi
89
A. Poggi
90
Unapplicazione 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 delloperazione del servizio di persistenza che viene invocata
A. Poggi
91
new
Rimosso delete()
Staccato
garbage
A. Poggi
92
Lo stato transiente
un oggetto creato con unoperazione new entra nello stato transiente, in quanto non ` (ancora) associato e con alcuna tupla della base di dati la vita di un oggetto nello stato transiente termina non appena non esiste pi` alcun oggetto che fa riferimento u ad esso (diventa disponibile per il servizio di garbage collection) Hibernate non fornisce alcun servizio di roll-back per gli oggetti nello stato transiente
A. Poggi
93
Lo stato persistente
un oggetto nello stato persistente ` un oggetto che ha e associato un identicatore proveniente dalla base di dati un oggetto nello stato persistente ` sempre associato e ad un contesto di persistenza, ovvero ad un insieme di oggetti dellapplicazione sincronizzati rispetto alla base di dati il contesto di persistenza pu` essere considerato o come una cache di istanze associata allistanza sessione (istanza di Session) correntemente aperta: quando la sessione viene chiusa, la cache viene svuotata
A. Poggi
94
Il contesto di persistenza
il contesto di persistenza ` utile ai seguenti ni: e
per fare automatic dirty checking: quando il contesto di persistenza ` chiuso, lo stato della cache e ` propagato alla base di dati in maniera e transazionale tutte e sole le propriet` degli oggetti persistenti a che sono state modicate saranno aggiornate per fare write-behind: modiche agli oggetti nel contesto di persistenza sono propagate alla base di dati allinvocazione del metodo flush ottimizza gli accessi e riduce la durata del lock sul database
A. Poggi 95
per realizzare un raggio dellapplicazione allinterno del quale gli oggetti coinvolti sono tra loro consistenti, in modo tale da garantire (i) lidentit` a degli oggetti (i.e., una tupla di valori della base di dati ` associata al pi` ad un oggetto), (ii) il e u repeatable read per ottimizzare gli accessi, realizzando a tutti gli eetti una cache di primo livello
A. Poggi
96
Transazioni e Session
Allapertura di un nuovo oggetto della classe Session (metodo openSession() della classe SessionFactory) viene creata una nuova connessione JDBC con la base di dati di default, Hibernate imposta lautocommit a false, il che comincia a tutti gli eetti una transazione JDBC!
A. Poggi
97
quando viene invocato il metodo flush le modiche nel contesto di persistenza sono sincronizzate con la base di dati Attenzione: non viene eseguito commit, quindi lesito della transazione dipende dal DBMS sottostante ` necessario usare la classe transaction, con i suoi e metodi commit sia rollback N.B. Di default, il ushing della sessione avviene implicitamente al quando viene invocato il commit e prima di eseguire una query
A. Poggi
98
new(O)
save(o) saveOrUpdate(o)
N.B. Il metodo saveOrUpdate verica prima se loggetto occorre nella base di dati ed a seconda dellesito della verica, eettua unoperazione di INSERT o di UPDATE
A. Poggi
100
quando viene creato (i) invocando uno dei metodi get e load del servizio di persistenza, (ii) come risultato di una query, (iii) navigando il grafo degli oggetti a partire da unaltra istanza persistente
Session (Contesto di persistenza) openSession()
new(O)
save(o) saveOrUpdate(o)
N.B. I due metodi get e load si distinguono per il fatto che se lidenticatore non viene trovato, get restituisce null mentre load lancia una ObjectNotFoundException
A. Poggi
101
Lo stato staccato
un oggetto ` nello stato staccato se era nello stato e persistente ed ` stato poi cancellato dal contesto di e persistenza il riferimento alloggetto rimane ma pu`: o
divenire obsoleto a seguito di cambiamenti sulla base di dati non essere pi` sincronizzato con i valori ad esso u associati nella base di dati`, in quanto lapplicazione e stessa pu` modicare alcune sue propriet` o a
A. Poggi
102
un oggetto pu` essere reso staccato invocando uno tra o i metodi evict/ clear (che appunto cancellano listanza/tutte le istanze dalla cache del contesto di persistenza) alla chiusura della sessione, un oggetto entra nello stato staccato
Session (Contesto di persistenza) openSession() flush() close()
new(O)
save(o) saveOrUpdate(o)
A. Poggi
103
un oggetto nello stato staccato pu` tornare ad entrare o nello stato persistente attraverso linvocazione dei metodi update/saveOrUpdate
Session (Contesto di persistenza) openSession() flush() close()
update(o) saveOrUpdate(o)
setValue(v)
A. Poggi
104
quando si vuole fare tornare ad essere persistente un oggetto che ` nello stato staccato ed esiste gi` e a unistanza persistente corrispondente alla stessa tupla della base di dati, si invoca il metodo merge, che copia le propriet` delloggetto staccato sulle propriet` a a delloggetto persistente corrispondente alla stessa tupla della base di dati
Session (Contesto di persistenza) openSession() flush() close()
object o
getid(id)
merge(o)
A. Poggi
105
Lo stato rimosso
un oggetto ` nello stato rimosso se era nello stato e persistente ed ` invocato il metodo delete e ` stato schedulato per essere rimosso al termine di e ununit` di lavoro, ma fa ancora parte del contesto di a persistenza nch lunit` di lavoro non ` completata e a e
Session (Contesto di persistenza) openSession() flush() close()
load(id)
delete(o)
A. Poggi
106
un oggetto nello stato rimosso non deve essere riusato e devono essere rimossi tutti i riferimenti ad esso, in quanto sar` cancellato dalla base di dati a appena lunit` di lavoro sar` completata a a un oggetto nello stato rimosso diventa disponibile per il servizio di garbage collection al termine dellunit` di a lavoro
A. Poggi
107
Long-lived transactions
richiamo: tra il momento in cui si leggono i dati dal DB ed il momento in cui eventuali modiche si rendono persistenti pu` trascorrere molto tempo o si applica il pattern session-per-conversation: ` e necessario disabilitare il ushing automatico chiamando il metodo setFlushMode(FlushMode.MANUAL) quando la sessione ` aperta e
A. Poggi
108
lisolamento ` garantito in quanto, abilitando il e locking ottimistico, le modiche fatte in transazioni concorrenti sono riconosciute latomicit` ` garantita dal fatto che il ushing viene a e eseguito solo al termine della transazione, e se la sessione viene chiusa senza fare il ushing, la transazione viene abortita
A. Poggi
109
A. Poggi
110
Hibernate legge il result set e sulla base del le di mapping denito per la classe Category, analizza le colonne restituite: per ogni colonna restituita, verica se ` mappata su di una propriet` della classe, e se lo `, e a e popola la suddetta propriet` e restituisce una lista di a oggetti caricati dalla base di dati Attenzione: questo meccanismo funziona correttamente solo se si usano delle query SQL semplici come quella su specicata...
A. Poggi
111
A. Poggi
112
A. Poggi
113
Il pattern di programmazione che useremo prevede la denzione di uninterfaccia che comprende tutte le operazioni di persistenza di base (CRUD e metodi di ricerca) necessarie per ogni classe persistente
A. Poggi
114
GenericDAOHibernate<T,ID>
GenericUserDAO<Item,int> GenericDAOHibernate<T,ID>
GenericDAOHibernate<T,ID>
A. Poggi
115
Generica super-interfaccia
Raggruppa tutte le operazioni CRUD di base condivise da tutte le classi persistenti
public interface GenericDAO<T,ID extends Serializable> { T findById(ID id); T makePersistent(T class); void makeTransient(T class); }
A. Poggi
116
A. Poggi
117
public void setSession (Session s) { this.session = s; } protected Session openSession(){ if (session==null) session = HibernateUtil.getSessionFactory(). openSession(); return session; } protected Session getSession(){ if (session==null) session = HibernateUtil.getSessionFactory(). getCurrentSession(); return session; } public Class<T> getPersistentClass(){ return persistentClass; } public T findById(ID is) { T class = (T) getSession.load(getPersistentClass(),id);
A. Poggi
118
return class; } public T makePersistent(T class) { getSession.saveOrUpdate(class); return class; } public void makeTransient(T class) { getSession.delete(class); } public void flush() { getSession.flush(); } public void clear() { getSession.clear(); } }
A. Poggi
119
A. Poggi
120
A. Poggi
121
Nota
Per realizzare unimplementazione che segue lapproccio DAO hand-coded ` necassario allo stesso modo, denire e unimplementazione generica e una sua sottoclasse per ogni classe persistente cf. lezione sullapproccio DAO allORM
A. Poggi
122
A. Poggi
123