Hibernate
HibernateObjectRela+onalMapping
ProgrammazionediApplicazioniDataIntensive
LaureainIngegneriaeScienzeInforma4cheDISI–UniversitàdiBologna,Cesena
G.Domeniconi,G.Moro,R.PasoliniDISIUniversitàdiBologna,Cesena
Hibernate
Hibernate
• HibernateORMèunframeworkJavaopensourceperl’Object-Rela+onalMappingampiamenteu+lizzato– UsatocomecomponenteinaltrisoMwareeframework,inclusoanche
inWebRa+o– SiintegraconaltriframeworkJavaampiamenteu+lizza+(es.Spring)
• FornisceunaAPIsempliceperleggereescrivereoggeTJavada/aundatabase
• Èun’implementazionedellaJavaPersistenceAPI(JPA)– Sipuòusarecometaleoppure(comefaremoinseguito)conlapropria
API,cheoffremaggiorifunzionalità
• EsistonoaltrelibrerieHibernatechesiintegranoall’ORM– AdesempioSearch(chevedremoinseguito)perlaricercatestuale
2DataIntensiveApplica+ons
Hibernate
Cara[eris+chediHibernate
• Ilmappingtraclassietabellepuòesseredichiarato– tramiteunoopiùfileXML– tramiteannotazionisulleclassidelmodelloda+
• siusanoleannotazionidiJPAequellepropriediHibernate
• Leclassidelmodellosonosemplicibean– èsufficientecheneseguanolaconvenzione(metodiget/set)– nondevonoestendereclassioimplementareinterfaccespecifiche
• GlioggeTpossonoesserereperi+daldatabaseinduemodi– unoperunotramiteilloroiden+ficatore– tramiteinterrogazioni,chepossonoessereespresseinvarimodi,tra
cuiHibernateQueryLanguage(HQL)
3DataIntensiveApplica+ons
Hibernate
Hibernate:configurazionegenerale
• PerusareHibernateinun’applicazione,ènecessariodefinirealcuneimpostazionigenerali– connessionealdatabase,asceltatra
• parametridiconnessioneJDBC(classedriver,URL,credenzialid’accesso)• sorgenteda+connome,accessibileviaJavaNamingDirectoryInterface
– diale[oSQLdausare,asecondadelRDBMSusato– riferimen+afileXMLe/oclassien+tàcontenen+laconfigurazionedel
mappingtraclassietabelle
• Esistonomoltealtreimpostazionifacolta+ve,tracui:– impostazionecreazioneautoma+caschema(nonlausiamo)– opzionididebug(es.stampainoutputdeicomandiSQLimpar++)
• LaconfigurazioneèdefinitainunfileXMLconnomestandardhibernate.cfg.xml
4DataIntensiveApplica+ons
Hibernate
Esempio:filehibernate.cfg.xmlusatonellawebappdie-commerce
<hibernate-configuration>
<session-factory>
<!-- nome JNDI della sorgente dati per accedere al DB -->
<property name="hibernate.connection.datasource"> java:comp/env/psqlpool </property>
<!-- dialetto SQL da usare per interagire col RDBMS usato -->
<property name="hibernate.dialect"> org.hibernate.dialect.PostgreSQL9Dialect </property>
<!-- schema del database in cui si trovano le tabelle -->
<property name="hibernate.default_schema">estore</property>
<!-- classi entità contenenti annotazioni per il mapping -->
<mapping class="it.unibo.dia.estore.model.Category"/>
<mapping class="it.unibo.dia.estore.model.Invoice"/>
<mapping class="it.unibo.dia.estore.model.InvoiceEntry"/>
<mapping class="it.unibo.dia.estore.model.Product"/>
<mapping class="it.unibo.dia.estore.model.User"/>
</session-factory>
</hibernate-configuration>
5DataIntensiveApplica+ons
U+lesetu[eletabelleconida+sitrovanoinunostessoschemadiversodapublic
Hibernate
Hibernate:ConfigurationeSessionFactory
• UnaconfigurazionediHibernateèrappresentataarun-+medaunogge[oConfiguration – Configuration cfg = new Configuration()
• Didefaultquestaèimportatadalfilehibernate.cfg.xml all’avviodell’applicazione – cfg.configure() // carica configuraz. da file – Sipuòanchespecificareunaltrofileoconfiguraretramitecodice
• All’avviodell’applicazionesicreadallaconfigurazioneunogge[oSessionFactory – SessionFactory sf = cfg.buildSessionFactory() – Questoogge[osiinterfacciaadundbspecificoedèunicopertu[a
l’applicazioneeservepercrearesessioni– dinormavieneresoaccessibileglobalmente,ades.comemembrosta+co
diunaclasseocomea[ributoalivellodiapplicazione6DataIntensiveApplica+ons
Hibernate
Hibernate:Session
• DaunaSessionFactorysiapreunasessione– Session s = sf.openSession() danonconfondereconle
sessioniHTTP • Unasessioneèunaunitàdilavoro(workingunit),unasequenza
dioperazionicorrelatelogicamente,manonèunatransazione– lasessionenonhaadesempioleproprietàACIDdellatransazione
• L’ogge[oSessionforniscemetodi(chevedremoinseguito)perleggereescrivereoggeTpersisten+neldatabase
• Ognisessionedeveessereusatadaunsingolothread– SepiùthreadusanoHibernate,ciascunoapreunapropriasessione
• lesessionisichiudonocolmetodocloseeciòchiudelaloroconnessionealdbliberandorisorse– SessionèAutoCloseable:sipuòusarecomerisorsaintry – perlimitarelerisorseu+lizzate,lasessionesiapre/chiudeadognirequest
DataIntensiveApplica+ons 7
Hibernate
Hibernate:Transaction
• Leoperazionisuida+sonoeseguitecontransazioni• LetransazioniinHibernatecorrispondonoatransazionisul
database(atomiche,consisten+,isolate,durature)• Ognitransazionedeveesserecontenutainun’unicasessione• Inunasessionepossonosvolgersiunaopiùtransazioni• Unatransazione,rappresentatadaunogge[oTransaction,
puòessereo[enutadaSession • Transaction tx = s.beginTransaction(); • Sull’ogge[oallafinesichiamanocommitorollback8 • Letransazionisonoaperte/chiusedaicontrollerdell’applicazione
– nelnostrocasodistudiociòavvienea[raversoifiltri
8DataIntensiveApplica+ons
Hibernate
ConcorrenzaconHibernate:OggeTeDB
• Unawebappècostantementeina[esadirichiesteedesegueoperazioniinrispostaatalirichieste
• Piùrichiesteconcorren+sonoges+teinparallelodalwebserveraTvandopiùthreadsulmedesimocodice– alivellodeldblaconcorrenzadeveessereges+taconconnessionie
transazionidis+nte– hibernateforniscemeccanismidilockeversioningperges+rela
concorrenzaalivellodioggeT,similiaquellideiDBMS– L’approccio+picoèdiu+lizzareunasessionehibernateperciascuna
richiesta(pa[ernsession-per-request)– Lasessioneèapertaalricevimentodellarichiestaechiusaunavolta
costruitalarisposta,rilasciandocosìlaconnessionealdb– Unatransazionesipuòaprireechiuderecontestualmenteallasessione– Èpossibileusareunfiltroservletperges+reiltu[oautoma+camente
9DataIntensiveApplica+ons
Hibernate
Modificheconcorren+aglioggeT:Locking• Unogge[opuòessereges+todapiùsessionicontemporanee
– InmemoriasiavrannomolteplicioggeTJava(unoperognisessione)cherappresentanolastessatuplasulDB
• Modificheconcorren+possonocomportareinconsistenze– Es.:lostessoogge[oèrecuperatodaduesessioniequestetentanodi
salvaremodificheinconfli[otraloro• Perevitareanomaliedovuteallaconcorrenza,Hibernate
forniscedueapprocci:– LockingoKmis4codeglioggeTdoveunaproprietàdell’ogge[odeve
indicarnelaversionea[uale– primadiaggiornareida+sulDB,lasessioneHibernateverificache
altresessioninonabbianosalvatounanuovaversionedell’ogge[o• selaversionedell’ogge[oècambiatainnescaun’eccezioneconcuiges+rel’anomaliaalivelloapplica+vo
– Lockingpessimis4coacquisiscelocksuogggeTconSession.lockIllockèrilasciatoalterminedellatransazionecorrente
10DataIntensiveApplica+ons
Hibernate
SessioniHTTP:ConcorrenzaeTransazioni
• ÈopportunocheunasingolatransazionesulDBnonsiainframmezzatadainterazioniutentediunasessioneHTTP
• LesessioniHTTPcos+tuisconotransazioniapplica4ve:èresponsabilitàdell’applicazionemantenernel’isolamento– Un’unicatransazioneapplica+vapuòincluderepiùtransazionisuDB– Unatransazioneapplica+vaèatomicasesolamentel’ul+ma
transazionesuDBchecompiecomportal’aggiornamentodida+• Pergaran+real+livellidiconcorrenzaescalabilità,siapplicail
controllodiconcorrenzaoTmis+coconversioning– Nonvengonoacquisi+lockesplici+suglioggeT,maseneverificala
consistenzaprimadiscriveregliaggiornamen+suDB– Hibernatepuòges+reautoma+camenteilcontrollodelleversionidegli
oggeT,anchea[raversomolteplicisessioniHibernate– Inalterna+va,ilcontrollopuòessereacaricodell’applicazione
DataIntensiveApplica+ons 11
Hibernate
HibernateesessioniHTTP
• Inunawebapp,unasessioneHTTPèunoscambiodirichiesteerisposteconlostessoclientacuisipossonoassociareda+– Esempidida+disessioneinunawebappdie-commerce(comeilnostro
caso)sonol’utenteauten+catoeilcarrellodellaspesa• U+lizzandoHibernatecolpa[ernsession-per-request,aduna
sessioneHTTPcorrispondonopiùsessioniHibernate
• Nellanostrawebapp,nellasessioneHTTPteniamosalva+
solamentegliIDdeglioggeT(utenteeprodoTnelcarrello)– usiamoSessionManagerpero[enereglioggeTdovenecessari– inquestomodosiminimizzal’occupazionedimemoriapersessione
• Inseguito,con“sessione”intenderemounasessioneHibernate
DataIntensiveApplica+ons 12
SessioneHTTPRichiesta+rispostaHTTP
Sessione+transazioneHibernateRichiesta+rispostaHTTP
Sessione+transazioneHibernateRichiesta+rispostaHTTP
Sessione+transazioneHibernate
Hibernate
Dichiarazionemappingtraclassietabelle
• PersalvareereperireoggeTnelDB,ènecessariodefinireilmappingtraleloroclassieletabelle– Leclassisonoquellechecos+tuisconoilmodeldell’applicazione
• GlioggeTdevonoesseredeibean,cheespongonoproprietà– Lerela+veclassidevonodefinire(almeno)uncostru[oresenza
argomen+emetodiget/setperciascunaproprietà
• Ogniproprietàèassociataadunaopiùcolonnesuldatabase– piùcolonneselaproprietàcorrispondeadunogge[ocomposto/
incorporato
• Deveesistereunaproprietàcheiden+fichil’ogge[o• Classeemetodiget/setnondevonoesseredichiara+final
– Alcunefunzionalitàcreanodinamicamenteclassicheliestendono
13DataIntensiveApplica+ons
Hibernate
Definizionemappingtramiteannotazioni
• LeinformazionisulmappingdiunaclassesipossonointegrarenellastessatramiteannotazioniJava– inalterna+vaèpossibiledefinireilmappingtramiteXMLper
manteneresepara+gliaspeT,mausiamoleannotazioninelleclassi
• HibernatesibasasulleannotazionidefinitedallaJavaPersistenceAPI(packagejavax.persistencediJavaEE)– Facileintegrazioneosos+tuzioneconaltriframeworkcompa+bili– Tu[eleannotazionichevedremo(senonindicatoaltrimen+)sonoJPA– Hibernateintroduceancheannotazioniproprieperfunzionalità
aggiun+ve(packageorg.hibernate.annotations)
• Ogniclasseannotatavadichiaratanellaconfigurazione – contag<mapping class="…" />inhibernate.cfg.xml – oppureconmetodoaddAnnotatedClassdiConfiguration
14DataIntensiveApplica+ons
Hibernate
Annotazionidiunaclasse
• Ogniclassepersistente(en4tà)vaannotatacon@Entity – èun’annotazionedijavax.persistence.Entity(JPA)
NONorg.hibernate.annotations.Entity
• Inaggiunta,sipuòu+lizzarel’annotazione@Tableperspecificareilnomedellatabellanell’a[ributoname – Didefault,èugualealnomedellaclasseinminuscolo
@Entity
@Table( name = "user" )
public class User { ... }
• All’internodellaclasse,vannoannota+imetodigetrela+vialleproprietàdasalvareneldatabase
15DataIntensiveApplica+ons
Datocheilnomedellatabellaèugualeaquellodellaclasse,inquestocaso@Tableèfacolta+va
Hibernate
Mapping:proprietàprimi+ve
• Unaproprietàdi+poprimi+vosimappaadunasingolacolonnadel+poSQLcorrispondente– TipiJavasupporta+:primi+vi(int,double,…),String,Date,…– TipiSQLcorrisponden+:INTEGER,REAL,VARCHAR,TIMESTAMP,…
• Questeproprietàsonopersisten+didefault– ossianonoccorreannotazione,masipuòdichiararecon@Basic
• Unaproprietànonpersistentevaannotatacon@Transient – U+leperproprietàderivate,ilcuivaloreècalcolatodaaltre
DataIntensiveApplica+ons 16
private Date birthDate;
@Basic // annotaz. facoltativa
public Date getBirthDate() {
return birthDate;
}
@Transient
public int getAge() {
calcolaetàdabirthDate…}
Hibernate
Mapping:configurazionecolonne
• @Columnspecificalacolonnacorrispondenteadunaproprietà • Conl’a[ributonamesiindicailnomedellacolonna
– didefault,ilnomedellacolonnaèugualeaquellodellaproprietà
• Sipossonospecificarealtreproprietà,tracui:– length:lunghezzamassimadiunastringa– nullable:sefalse,lacolonnaèimpostatacomeNOT NULL – unique:setrue,allacolonnaèassociatounvincolodiunicità– precision,scale:a[ribu+percolonnedi+ponumerico– HibernateusaquesteinformazionisedevegenerareloschemadelDB
@Basic
@Column( name="name", length=40, nullable=false )
public String getName() {…}
DataIntensiveApplica+ons 17
definizionerisultantecolonnainSQL:name VARCHAR(40) NOT NULL
nomefacolta+vo(ugualeaproprietà)
Hibernate
Mapping:Iden+ficatori
• Ogniclassepersistentedevedichiarareun’unicaproprietàchefungadaiden+ficatoreunivoco(ID)deisuoioggeT
• QuestacorrispondeallachiaveprimarianellatabelladelDB– Selachiaveprimariaècos+tuitadapiùcolonne,varappresentatacon
un’unicaproprietàusandounogge[oincorporato(spiegatoabreve)
• Laproprietàiden+fica+vavaannotatacon@Id• Anchequisipuòusare@Columnperindicareilnomeela
proprietàdellacolonnacorrispondentesulDB@Id
@Column( name="oid" )
public int getId() { … }
DataIntensiveApplica+ons 18
Hibernate
GenerazionedegliIden+ficatori
• L’IDserveadiden+ficarelatupladiunogge[oneldatabase– L’IDdeveesseredis+ntodatuTquelligiàesisten+perlastessaen+tà
• Unogge[ocreatodall’applicazionepuòinizialmenteesseresenzaID,manedeveavereunounavoltasalvatonelDB
• L’IDpuòessereimpostatodalcodicechecreal’ogge[o,maèpiùaffidabilegenerarloinautoma+co
• PossiamosceglieretradiversestrategiepergeneraregliIDdiciascunaen+tà,divisibiliindueapprocci– Hibernategeneraautonomamentel’ID(diversimodipossibili)– L’IDègeneratotramitefunzionalitàspecifichedelRDBMS(tramitead
es.sequenzeecolonnedi+poserialinPostgreSQL)
DataIntensiveApplica+ons 19
Hibernate
Mapping:GeneratoridiID
• Conl’annotazione@GeneratedValueeilsuoparametrogeneratorsiindicailnomediunastrategiadigenerazione
• Con@GenericGeneratorsidefinisceunastrategiaconunnome(name)eun’implementazione(strategy),cos+tuitadalnomediunaclasseounnomepredefinitodiHibernate– @GenericGeneratorèspecificadiHibernate,nonèinJPA
• Adesempiolastrategiasequenceusalesequenzeconincrementoautoma+codiPostgreSQL(ealtriRDBMS)
@Id @Column( name="oid" )
@GenericGenerator(name="seq", strategy="sequence")
@GeneratedValue( generator="seq" )
public int getId() { ... } DataIntensiveApplica+ons 20
Hibernate
OggeTIncorpora+
• Abbiamovistofinoraproprietàdi.piprimi.vi,con+piequivalen+inSQL
• Seilvalorediunaproprietàèunriferimentoadunaltroogge[opersistente,vages+tacomeassociazione(vedidopo)
• Unogge[oèinveceincorporato(embedded)inunogge[opersistentesenecos+tuisceparteintegrante– Nonècondivisoinaltreassociazioni(e.g.da+diconta[odiunutente)– Ilsuociclodivitaèlegatoaquellodell’ogge[ochelocon+ene– CorrispondeinUMLadunarelazionedicomposizionetraclassi
• Leproprietàdell’ogge[oincorporatorimangonomemorizzatenellastessatabelladell’ogge[opersistentechelocon+ene– es.lecolonnesuldbdell’ogge[oincorporato(conta[o)sono
contenutenellatabelladimappingdell’ogge[oincorporante(utente)
DataIntensiveApplica+ons 21
Hibernate
U+lizzodegliOggeTIncorpora+
L’usodioggeTincorpora+èu+leper• separareconce[ualmenteleproprietàdiun’en+tà
– es.:telefono,e-mailetc.sipossonoinglobareinunogge[ocontaK• definireuninsiemediproprietàpresen+inpiùen+tà
– es.:contaKpuòappariretraleproprietàdiuncliente,unfornitoreecc.
DataIntensiveApplica+ons 22
id company_name phone mail …
12 Acme Inc. +1234… …@… …
23 Northwind +5678… …@… …
… … … … …
id username phone mail …
1234 bobby +4321… …@… …
5678 tom86 +8765… …@… …
… … … … …
Supplier id = 12 company_name = Acme Inc. contacts = ...
User id = 1234 username = bobby contacts = ... ContactInfo
phone = +1234… mail = …@…
...
ContactInfo phone = +4321… mail = …@…
...
Hibernate
Mapping:OggeTIncorpora+
• Laclassediunogge[oincorporatosidichiara@Embeddable
• All’internodellaclasse,siusanoleordinarieannotazioniperilmappingdellesingoleproprietà(@Basic,@Column,...)
• Nell’en+tà,laproprietàchecon+enel’ogge[oincorporato(contuTisuoia[ribu+)vadichiarata@Embedded – Opzionalmente,conannotazioni@AttributeOverridesipuò
modificareilmappingdichiaratonellaclasse@Embeddable
• Unaproprietà@EmbeddedconvalorenullsirappresentanelDBconivaloriditu[elecolonneincorporatepariaNULL
• Un’ogge[oincorporatopuòfungeredaID,nelqualcaso– laclasse@EmbeddabledeveessereSerializable – invecedi@Ided@Embeddedsiusa@EmbeddedId
23DataIntensiveApplica+ons
Hibernate
Ogge[oReviewincorporatoinInvoiceEntry
@Embeddable
public class Review {
private int score;
private String summary;
private String text;
public Review() {}
@Column( name = "score" )
public Integer getScore() {...}
@Column( name="review_summary") # nome dell’attributo sul db
public String getSummary() {...}
altri metodi...
}
@Entity
public class InvoiceEntry {
campi...
private Review review;
public InvoiceEntry() {}
altri metodi...
@Embedded
public Review getReview() {
return review;
}
public void setReview(...) {...}
}
24DataIntensiveApplica+ons
Hibernate
Associazioni
• Comedalezioneprecedente,leassociazionicos+tuisconolegamitraoggeTpersisten+,secondodiversecardinalità– es.uno-a-mol4: ogniutenteeffe[uapiùordini
ogniordineèeffe[uatodaunsoloutente– es.mol4-a-mol4: adogniprodoMosonoassociatepiùcategorie
ognicategoriacon+enepiùprodoK
• Un’associazioneunidirezionaleodireMadaAaBcomportalapresenzanell’en+tàAdiunaproprietàilcui+poèl’en+tàB– Nelcasodiunaproprietà*-a-mol4,il+poèunacollezionediB
• SeancheBdefinisceunaproprietàdi+poA,l’associazioneènavigabilebidirezionalmente– es.l’associazioneA→Bmol4-a-unoèbidirezionaleseoltreallaproprietà
dire=amol4-a-unoA→Bèdefinitalaproprietàinversauno-a-mol4B→A
DataIntensiveApplica+ons 25
Hibernate
Mapping:Proprietàmol+-a-unoeuno-a-uno
• Adun’associazioneA→Bmol4-a-uno,percuiadogniogge[oAneèassociatounosolodi+poB,corrispondeunaproprietànellaclasseAchehalaclasseBcome+po– ades.ogniinvoice(A)èassociataadunsoloutente(B)
• Ilge[erdiunaproprietàmol4-a-unosiannota@ManyToOne• Conl’annotazione@JoinColumnsiindicalacolonnadiA
contenentelachiaveesternachereferenzialatabelladiB– Hapiùomenoglistessiparametridi@Column,inclusoname
# Classe Invoice
@ManyToOne
@JoinColumn(name="user_oid")
public User getUser() {…}
• Perun’associazioneuno-a-unosiusainmodoequivalentel’annotazione@OneToOne
DataIntensiveApplica+ons 26
id … user_oid
… … …
… … …
invoice (A)
id …
… …
… …
user (B)
Hibernate
Associazionia-mol+:Collezioni
• AssociazioniB→Adi+pouno-a-mol4omol4-a-mol4comportanocheadunogge[oBsianoassocia+piùoggeTA– es.ogniutente(B)puòeme[erepiùordini(A)
• Questorichiedechelarela+vaproprietàdellaclasseBabbiapervaloreunacollezionedioggeTdi+poA
• Un+podicollezionecomuneèl’insieme,contenenteoggeTdis+n+,rappresentatoinJavadall’interfacciaSet – diversodaList,listaordinatadioggeTconpossibiliduplica+
• Èprassiinizializzareunaproprietàdi+poSetaduninsiemevuotomodificabile(ades.unHashSet)
private Set<Invoice> orders = new HashSet<>();
public Set<Invoice> getOrders() { return orders; }
public void setOrders( Set<Invoice> orders ) { ... } DataIntensiveApplica+ons 27
Hibernate
Mapping:associazioniuno-a-mol+
• Unaproprietàuno-a-mol4B→Asiannotacon@OneToMany sullaclasseB
• SelatabelladiAcon+eneunacolonnaconlachiaveesternadiB,siusa@JoinColumnperindicarequalè– Con+enealcunedellestesseproprietàdi@Column,inclusaname – Perun’associazionediquesto+poHibernateconsigliaperòdiusareuna
tabelladijoincomeperunamol+-a-mol+(vediamodopo)
public class User {
@OneToMany
@JoinColumn( name="user_oid" )
public Set<Invoice> getOrders() { ... }• Questaproprietàvadichiaratacomeinversa,vediamocome....
28DataIntensiveApplica+ons
QuestadichiarazioneènellaclasseUser(B),malacolonnauser_oid
ènellatabellainvoice(A)
Hibernate
Associazionibidirezionali:proprietàdire[eeinverse
• Un’associazionebidirezionaleA→BprevedecheinAsiadichiarataunaproprietàdi+po(collezionedi)Beviceversa
• Inun’associazionebidirezionale,unadelledueproprietà(A→B)vadichiaratadireMael’altra(B→A)inversa– Sidicechel’en+tàAèproprietaria(owner)dell’associazione– Un’associazioneunidirezionalecomprendesolamentelapartedire[a
• Quandoun’ogge[oAoBèle[odalDB,glioggeTassocia+sonoaccessibiliinentrambiledirezionidell’associazione
• Quandounogge[ovieneaggiornato/inseritosulDB,Hibernateintervienesullatodire[odell’associazione– Hibernateignoraillatoinversoperevitarepossibiliincoerenze– es.ordini-uten+:quandounutenteinserisceunordine,losiaggiunge
intervenendosullaclasseordini(owner)enonsullaclasseuser
DataIntensiveApplica+ons 29
Hibernate
Mapping:associazionidire[eeinverse
• Perdichiarareun’associazionebidirezionale,nevannoconfigurateentrambelepar+(dire[aeinversa)
• Lapartedire[adeveessereconfiguratacomevistonelleslidepreceden+(es.colonnaotabelladijoin)
• Laparteinversadeveinvecedichiararesolounriferimentoallacorrispondentedire[a
• Adesempio,definiamodire[al’associazionedagliordiniagliuten+(adogniordinecorrispondeunutente)einversaquellanell’altradirezione– Quandosisalvaunogge[oordinenelDB,vieneaggiornataanchela
suaproprietàconl’informazionesull’utentechel’haeseguito– QuandosisalvaunutentenelDB,ida+suisuoiordinisonoignora+
DataIntensiveApplica+ons 30
Hibernate
Mapping:proprietàuno-a-mol+inverse
• Unaproprietàuno-a-mol4,i.e.inversadiunamol4-a-uno,siannotasolamentecon@OneToMany,indicandoinmappedByilnomedellaproprietàdire[acorrispondente– HibernateuseràlaconfigurazionedellaproprietàuserdiInvoice
public class User { ...
@OneToMany( mappedBy="user" )
public Set<Invoice> getOrders() { ... }
id … user_oid
… … …
… … …
invoice class User {
... getOrders() ...
}
@OneToMany( mappedBy = )
class Invoice { ... getUser() ...
}
@ManyToOne @JoinColumn( )
31DataIntensiveApplica+ons
id …
… …
… …
user
Hibernate
Mapping:associazionimol+-a-mol+
• Un’associazionemol4-a-mol4sibasasuunatabelladijoin– Tabellacontenenteunarigaconunacoppiadichiaviperognisingola
associazionetraunogge[oAeunogge[oB
• Laproprietà(dire[aoinversa)siannotacon@ManyToMany • Sullaproprietàdire[asiusa@JoinTableperfornire
informazionisullatabelladijoin– name:nomedellatabella– joinColumns:colonna/erela+va/eall’en+tàproprietaria(A)– inverseJoinColumns:colonna/edell’en+tàassociata(B)
• Sullaproprietàinversa(analogamentealleuno-a-mol+)sispecificanell’a[ributomappedBydi@ManyToManyilnomedellaproprietàdire[acorrispondente
32DataIntensiveApplica+ons
Hibernate
Mapping:associazionimol+-a-mol+,Esempio
• Proprietàdire=apublic class Product { ...
@ManyToMany
@JoinTable( name="category_product",
joinColumns=@JoinColumn(name="product_oid"),
inverseJoinColumns=@JoinColumn(name="category_oid") )
public Set<Category> getLabels() { ... }
• Proprietàinversapublic class Category { ...
@ManyToMany( mappedBy="labels" )
public Set<Product> getItems() { ... } 33DataIntensiveApplica+ons
product_oid category_oid
... ...
category_product
oid ...
... ...
product
oid ...
... ...
category
Hibernate
ImplementazionediequalsehashCode
• SesiusanoSetdioggeTdiunaclasse,questadeveimplementarecorre[amenteimetodiequalsehashCode – x.equals(y)indicaseidueoggeTsonoseman4camenteuguali– hashCode()implementaunafunzionehashusatainternamenteneiSet:sex.equals(y)allorax.hashCode()==y.hashCode()
• Hibernatepuòrappresentarelastessaen+tà(unariganeldatabase)conpiùoggeTJava(indiversesessioniaperte):equalsdeveindicarecheques+oggeTsonouguali
• L’approcciopiùovvioèconfrontaregliID(chiaviprimarie)– Daperòproblemiades.peroggeTnonsalva+neldatabase,senzaID
• L’approccioconsigliatoèdiconfrontaregliiden+ficatorifunzionalideglioggeT(es.ilnomedegliuten+)– Ques+devonoessereunivocieimmutabiliperchéiSetfunzionino
34DataIntensiveApplica+ons
Hibernate
EsempidiimplementazionidiequalsehashCode
• Implementazionebasatasuchiaveprimaria
public class Product {
@Id
public int getId() {...}
public boolean equals(Object ob) {
if (!(obj instanceof Product))
return false;
return
((Product) ob).getId() == getId();
}
public int hashCode() {
return getId();
}
}
• Implementazionebasatasuiden+ficatorefunzionale
public class User {
@Basic
public String getName() {...}
public boolean equals(Object ob) {
if ( !(obj instanceof User) )
return false;
return ((User) ob).getName()
.equals(getName());
}
public int hashCode() {
return getName().hashCode();
}
}
35DataIntensiveApplica+ons
Hibernate
Mapping:ordinamentocollezioni
• LerigheinunatabelladiunDBnonhannounordinelogico– UnaquerysenzaunaclausolaORDER BYleres+tuisceinunordine
dipendentedalRDBMSspecifico(ades.ordinateperchiaveprimaria)• Tu[aviaèspessoopportunoo[enerecollezionidioggeT
ordinatesecondouncriteriospecifico– inpar+colareperpresentarleall’utente,ades.ordinielenca+perdata
• Tramitel’annotazione@OrderByèpossibiledeterminarel’ordineincuio[enereglioggeTassocia+– Sispecificanounaopiùproprietàdellaclasseassociata,suciascunasi
specificaopzionalmenteASC(dalprimoall’ul+mo)oDESC(viceversa)– HibernateusaORDER BYpero[enereda+nelgiustoordinedalDB
@OneToMany( mappedBy=... )
@OrderBy( "date DESC" ) // dal più recente
public Set<Invoice> getOrders() { ... }
DataIntensiveApplica+ons 36
Hibernate
Accessoadunogge[operchiaveprimaria
• Perrecuperareunospecificoogge[odaldatabaseservono– il+podiogge[o(informadistringaodiogge[oClass)– l’iden+ficatore,ovverolachiaveprimaria
• L’interfacciaSessionforniscedue+pidimetodi(nomicontrointui4vi,mausa4percompa4bilitàconversionipreceden4)– getres+tuisceunogge[oinizializzato(comportandoseserveun
accessoaldatabase)onullsel’ogge[oconlachiavedatanonesiste– loadinveceres+tuiscesempreunogge[oassumendocheneesista
unoconl’IDdatoechepuònonessereinizializzato• u+leseservesoloilriferimentoall’ogge[o• quandositentadiaccedereall’ogge[o,sihaun’eccezionesenonesiste
Session session = ... ; int id = ... ;
User user = (User) session.load( User.class, id );
37DataIntensiveApplica+ons
Hibernate
AccessoaglioggeTassocia+
• Pero[enereunogge[ocompleto,andrebberorecupera+glioggeTassocia+adesso,quelliassocia+alorovoltaecosìvia– SIpuòo[enereunagrandequan+tàdida+,comediscussoperiDAO
• Perevitareciò,Hibernatedidefaultcaricaida+deglioggeTassocia+soloquandovisiaccedelaprimavolta(lazyfetching)– Perfarciò,Hibernatecreainternamentedeiproxy,oggeTche
estendonoclassien+tàecollezionipercaricareida+surichiesta• Sonoinvececarica+subito(eagerfetching)didefaultvaloridi
proprietàscalari(@Basic)eoggeTincorpora+• Lastrategiaperogniproprietàsipuòimpostarecon
l’a[ributofetchdelleannotazioni@Basic,@ManyToOne,…– @ManyToMany( fetch = FetchType.EAGER ) public Set<Category> getLabels() { … }
DataIntensiveApplica+ons 38
Hibernate
HibernateQueryLanguage
• NeiRDBMS,èpossibileeseguirequerySQLpero[enereda+daldatabase,filtrarli,combinarli,aggregarli…
• UnasoluzioneORMcompletadevefornireunmeccanismosimile,macompa+bilecolmodelloadoggeT– classien+tàeproprietàinveceditabelleecolonne– (collezionidi)oggeTinvecedi(tabelledi)righe
• HibernateQueryLanguage(HQL)èunlinguaggiosimileaSQLperesprimerequerysuoggeTpersisten+neldatabase– èun’estensionediJPQL,illinguaggiodiquerydefinitoinJPA
• UnaqueryHQLpuòessereeseguitatramiteunogge[oSessioneres+tuisceunsingoloogge[oounalista(List)
39DataIntensiveApplica+ons
Hibernate
HQL:querydibase
• ConFROM,sispecificalaclassedeglioggeTdareperire– UsandosoloFROM,sireperisconotuTglioggeTdiquel+po– FROM User
• ConWHERE,sipossonospecificarecondizionisulleproprietà– FROM User WHERE name = 'bobby' – Sipossonousaremol+operatoripresen+ancheinSQL,ades.LIKE
• ConSELECT,sipossonoreperiresolospecificheproprietà– SELECT name FROM User
(sioTeneunalistadistringheinvecechedioggeTUser) • ConORDER BY,sipuòspecificarel’ordinedeglioggeT
– FROM User ORDER BY name ASC • Esistonopoialtrefunzionalità,quasitu[eequivalen+aSQL
– join,raggruppamento(GROUP BY),aggregazione(COUNT,SUM,…),…
40DataIntensiveApplica+ons
Hibernate
HQL:eseguireunaquery
• TramiteilmetodocreateQuerydiSession,sioTeneunogge[oQuerycheimplementaunaqueryHQLdata
Query query = s.createQuery( "FROM User" );
• Conlist,laqueryvieneeseguitaeunalistadioggeTrisultan+vieneres+tuita– Lalistaèdi+pogenerico,ènecessariouncastsullalistaosuglioggeT
List<?> results = query.list(); for ( Object obj : results )
doSomethingWithUser( (User) obj );
• Selaquerydeveres+tuireunsoloogge[o,losipuòo[eneredire[amenteconuniqueResult – Nessunrisultato→null;piùdiunrisultato→eccezione
User user = (User) query.uniqueResult();
41DataIntensiveApplica+ons
Hibernate
HQL:parametri
• Unaquerypuòcontenereparametrialpostodivaloricostan+– SimilarmenteaiPreparedStatementdiJDBC
• Isegnapos+periparametrisononomiprecedu+da“:”Query query = s.createQuery(
"FROM Invoice WHERE user = :who" );
• Primadieseguirelaquery,vannoimposta+ivalorideiparametriusandoimetodisetTipo(nome, valore) – Nelcasodiunogge[o,siusasetParameter
• Nelcasodien+tà,sipassacomevalorel’ogge[o,nonilsuoID– Pero[enereunogge[odall’ID,siconsigliadiusareSession.load
User user = ...; query.setParameter( "who", user );
42DataIntensiveApplica+ons
Hibernate
EsecuzionediunaqueryHQL
• Vediamoadesempiocomeimplementareunaquerycheres+tuiscagliordinidiundatoutentedalpiùalmenorecente– O[eniamogiàlostessorisultatocolmetodogetOrdersdiUser
• LaclasseQueryhaun’interfacciafluente:lechiamatesipossonoconcatenare
static final String HQL_ORDERS = "FROM Invoice WHERE user=:u ORDER BY date DESC";
Session s = ... ;
public List<Invoice> getOrders( User user ) {
return ( List<Invoice> ) s.createQuery( HQL_ORDERS ) .setParameter( "u", user ) .list();
}
Istruzioneunicaconchiamateametodi
concatenate
43DataIntensiveApplica+ons
Hibernate
QueryinHibernate:alterna+veaHQL
• HQLèada[operquerypredefinitesupportatedaHibernate• L’APICriteriaconsentediesprimerequeryinforma
object-orientedpiu[ostochetramitestringhe– ConSession.createCriteriasicreaunogge[oCriteria,a
cuisiaggiungonoclausoletramitechiamateametodi:addperaggiungerefiltriWHERE,addOrderperspecificarel’ordinamento,…
– U+lepercostruirequerydinamicamente(es.:l’utentepuòcercareprodoTselezionandofiltriasuasceltatramarca,fasciadiprezzo,…)
• Èanchepossibileeseguirequerydire[amenteinSQL(na4ve)– SiusaSession.createSQLQuery,passandolaquerySQL– DidefaultHibernateres+tuisceunarraydioggeTperogniriga,ma
tramitemetodisipuòimpostarelares+tuzionedioggeTen+tà– U+leperusarefunzionipropriedelRDBMSnonprevistedaHibernate
DataIntensiveApplica+ons 44
Hibernate
StatodeglioggeTinHibernate
Hibernateconsideratrepossibilista+perciascunogge[o• Unogge[ocreatofuoridaHibernate(es.connew)è
transitorio(transient)enoncorrispondeadunarigasulDB– es.:User user = new User()
• Unogge[oo[enutodaunaspecificaSessiondiHibernateèpersistente(persistent)edèges+todaessa– QuestoincludeoggeTo[enu+tramiteID,tramitequery,associa+,…– es.:User user = session.get( User.class, 42 )
• Quandolasessionecheges+sceunogge[opersistentevienechiusa(close),l’ogge[odiventa“scollegato”(detached)– Seunogge[oèscollegato,nonsipuòaccedereallesueproprietàcon
lazyfetchingnonancoracaricate(siavrebbeun’eccezione)
DataIntensiveApplica+ons 45
Hibernate
Modificadiunogge[opersistente
• Leproprietàdiunogge[opersistentepossonoesseremodificatenormalmentetramiteimetodiset – Pero[enerel’ogge[odamodificare(senonsihagiàunriferimento
adesso)èconsigliatousareSession.load • CiascunasessioneHibernate+enetracciadellemodifiche
apportateaglioggeTcheges+scenellapropriacache• Pereseguireicorrisponden+comandiUPDATE,bisogna
“scaricare”lacachenelDBinvocandoilmetodoflush – didefault,èinvocatoautoma+camentealcommitdiognitransazione
session.beginTransaction();
User user = (User) session.load( User.class, 42 );
user.setName( "Marvin" );session.getTransaction().commit();
46DataIntensiveApplica+ons
quisonoesegui+inordineUPDATEeCOMMITsulDB
Hibernate
Modificadiunogge[oscollegato
• Lemodificheadunogge[oscollegatosononormalmenteignorate,inquantononc’èunasessionecheloges+sca
• L’ogge[opuòperòesseretrasferitoadun’altrasessione– Es.:sileggeun’ogge[odaunasessione,l’utenteimpiegaalcuniminu+
amodificarlotramiteunaGUI,l’ogge[oèsalvatoconun’altrasessione• Ilmetodoupdateassociaunogge[odatoallasessione,che
ges+ràlesuemodifiche:l’ogge[oridiventapersistente– Erroreselostessoogge[o(conlostessoID)esistegiànellasessione– Ida+andrannopoisalva+nelDBconflushe/ocommitcomesopra
User user = session1.get( User.class, 42 );
// chiusura transazione e sessione 1
user.setName( "Marvin" );
// apertura sessione 2 e transazione
session2.update( user );
47DataIntensiveApplica+ons
Hibernate
Inserimentodiunogge[oneldatabase
• Unogge[otransitoriopuòessereinseritoneldatabase• Ilmetodoprimariopersalvareunogge[oèpersist
– QuestocomportaunINSERTsuldatabasealflushdellasessione• Ilmetodoalterna+vosaveres+tuiscel’iden+ficatore(chiave
primaria)assegnatoall’ogge[osalvato– SeèilDBagenerarel’ID,Hibernateeseguesubitol’INSERT
• Inentrambiicasi,l’ogge[otransitoriodiventapersistenteeges+todallasessionea[raversocuivienesalvato
session.beginTransaction();
User user = new User();
uso metodi set per inizializzare l’oggetto...
session.persist( user );session.getTransaction().commit();
48DataIntensiveApplica+ons
quisonoesegui+inordineINSERTeCOMMITsulDB
Hibernate
Eliminazionediunogge[odaldatabase
• Colmetododeletesieliminaunogge[odaldatabase– Perl’esa[ezza,sieliminalatupladell’ogge[odalDB– QuestocomportaunDELETEsuldatabasealflushdellasessione
• L’ogge[opassatopuòessereinunostatoqualsiasi:vieneconsideratosolamenteilsuoID– Idueesempiso[odannolostessorisultato:l’eliminazionedell’utente
conID42(transazioneomessaperbrevità)
• Inognicaso,l’ogge[oinJavapassaallostatotransitorio
49DataIntensiveApplica+ons
// con ogg. persistente
User user = session .load( User.class, 42 );
session.delete( user );
// con ogg. transitorio
User user = new User();
user.setId( 42 );
session.delete( user );
Hibernate
AltrimetodiperlapersistenzadeglioggeT
• Ilmetodoevictdissociaunogge[opersistentedallasessionecorrentesenzachiuderla,rendendoloscollegato
• Ilmetodomergeaggiornaunogge[opersistenteinsessione(giàcaricatoonodaldb)conida+delmedesimoogge[oscollegato– e.g.carrellodellaspesatraduerequestchevienescollegatoericollegato
allanuovasessionedell’ul+marequest– sipassacomeargomentol’ogge[oconida+dasalvare– Vieneres+tuitoinognicasounogge[opersistente
• IlmetodosaveOrUpdatescrivel’ogge[odatosuldb(rendendolopersistente)indipendentementedalsuostato– Sel’ogge[oègiàpersistenteeges+todallasessione,nonaccadenulla– Sel’ogge[oètransitorio,vienesalvato(persist)– Sel’ogge[oèscollegato,vieneassociatoallasessione(update)
50DataIntensiveApplica+ons
Hibernate
Riepilogosta+diunogge[oinHibernate
• Inomicolora+corrispondonoametodidiSession
Transitorio(transient)
Persistente(persistent)
scollegato(detached)
creazione
creazioneconnewoaltro
load get
orisulta4query
evict close
update merge
save persist
garbagecollec+on
51DataIntensiveApplica+ons
delete
saveOrUpdate
Hibernate
Operazioniincascata
• Normalmente,leoperazioniload,save,delete,...hannoeffe[osolamentesull’ogge[osucuisonoinvocate…
• …mainalcunicasidevonoapplicarsiancheaoggeTassocia+– Es.:quandounordine(Invoice)vienesalvato,sidesideraingenere
chesianosalvateanchelesuevoci(InvoiceEntry)
• OgniassociazionepuòessereconfiguratainmodocheleoperazionisianoeseguiteincascatasuglioggeTassocia+
• Conl’a[ributocascadedi@OneToOne,@OneToMany,…sipuòspecificarequalioperazionieseguireincascata– Nell’esempioso[o,aTviamolacascatasutu[eleoperazioni
(associazioneinversa)@OneToMany(cascade=CascadeType.ALL, mappedBy="invoice") @JoinColumn( name="invoice_oid" ) public Set<InvoiceEntry> getEntries() {…}
52DataIntensiveApplica+ons
Hibernate
Paginazionedigrandicollezioni
• NellewebappsonospessomostratecollezionidioggeT– ades.prodoTdiunacategoriaorisultan+daricerca,recensioni,...– informadilista(<ul>),tabella(<table>),galleriadiimmagini,...
• Lavisualizzazionediunacollezioneconungrandenumerodielemen+(migliaia,milioni,...)comportadiversiproblemi– latoserver:mol+da+devonoessereleTdaldatabaseedelabora+– iltrasferimentoviaretedellapaginarisultanterichiedetempo– latoclient:ilrenderingdellapaginanelbrowserrichiedemolterisorse
• E’prassidividereinpiùpaginecollezionipotenzialmentegrandi– l’utenteoTeneunapaginaspecificadellacollezione,iniziandodi
solitodallaprima,ciascunacontenenteunaquan+tàfissadielemen+– incimae/oinfondoallapaginasonoingeneremostra+ilnumerodi
paginee/odioggeTeilinkpernavigaretralepagine
53DataIntensiveApplica+ons
Hibernate
Paginazionedirisulta+diqueryHibernate
• SipossonoimpostarelequeryHibernateinmododares+tuiresolounapartedeirisulta+comple+– setMaxResultslimitailnumerodirigheres+tuite– setFirstResultfasìcheilDBsal+leprimeNrighe– metodidefini+siainQuery(HQL)cheinCriteria
• Fissatounnumerodielemen+Nperpagina,sipossonoo[enerequellidiunapaginapspecifica– Siassumequichep=0indichilaprimapagina
• Es.:conN=4elemen+perpagina,peraverelaterzapagina(p=2)dirisulta+diunaqueryquery.setMaxResults( 4 ) maxResults = N .setFirstResult( 8 ) firstResult = N·p .list()
DataIntensiveApplica+ons 54
012345678910111213
pag.0
pag.1
pag.2
pag.3
Hibernate
Codice:esempiodiqueryconpaginazione
• LaqueryHQLusatacomeesempiores+tuiscetuTglioggeTdiunadeterminatamarca,inordinealfabe+co
• Lepar+inazzurrocos+tuisconoilsupportoallapaginazionestatic final String HQL_PRODUCTS_OF_BRAND = "FROM Product WHERE brand = :brand ORDER BY name";
Session session;
public List<Product> getProductsOfBrandPaged( String brand, int itemsPerPage, int page ) {
return session.createQuery( HQL_PRODUCTS_OF_BRAND ) .setString( "brand", brand ) .setMaxResults( itemsPerPage ) .setFirstResult( page * itemsPerPage ) .list()
}
55DataIntensiveApplica+ons
page == 0→primapagina
Hibernate
PaginazioneconHibernate:limi+
• Lares+tuzionedirisulta+parzialisiapplicasoloallequery,nonsuproprietàoassociazionidioggeTpersisten+– Sipuòscrivereunaquerycheres+tuiscaglistessioggeTda+da
un’associazione– Inalterna+va,sipuòselezionareunapartedeirisulta+dopoaverli
o[enu+tuTdalDB(siriducecomunquelapaginaHTMLrisultante)
• Ognivoltachel’utenteselezionaunapaginadida+vienerieseguitalaquery– pertantoènecessariofisssareuncriteriodiordinamentopergaran+re
consistenzanellanavigazionetralepagine(perID,alfabe+co,...)
• Laquerypaginatanonfornisceilnumerodirecordedipagine– Perciòoccorreeseguireun’opportunaqueryaggiun+vapero[enereil
numerodielemen+chesarebberores+tui+dalDBsenzalimitazioni• InHQLsiusa“SELECT COUNT(*) …”(comeinSQL)
DataIntensiveApplica+ons 56