Upload
alyssa-edwards
View
28
Download
1
Embed Size (px)
DESCRIPTION
VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA. Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage. Část 6. Perzistentní vrstva. Prezentační vrstva "Jak aplikace vypadá". Servlety JSP Filtry. Business vrstva "Co aplikace dělá". Bezstavové EJB Beans Stavové EJB Beany - PowerPoint PPT Presentation
Citation preview
VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKAZbyněk Šlajchrt http://java.vse.cz/4it447/HomePageČást 6.
Perzistentní vrstva
Prezentační vrstva"Jak aplikace vypadá"
Prezentační vrstva"Jak aplikace vypadá"
Business vrstva"Co aplikace dělá"
Business vrstva"Co aplikace dělá"
Perzistentní vrstva"Co aplikace je"
Perzistentní vrstva"Co aplikace je"
ServletyJSPFiltry
Bezstavové EJB BeansStavové EJB BeanyMessage Driven Beany
JPA EntityJMS FrontyJMS Topiky
Entita
Perzistentní doménový objekt (PDO) Objekt
Atributy, metody, dědičnost ... Doménový
Doménou rozumíme oblast, pro kterou je aplikace navržena
Doménový objekt modeluje jsoucno z domény aplikace Faktura, objednávka, zboží, zákazník - z domény e-business Kniha, výpůjčka, čtenář, upomínka - z domény knihovnictví
Perzistentní Modelované jsoucno má trvalý charakter Data jsou uložena v úložišti, které je schopné uchovávat
data 'libovolně' dlouho
Entita v EJB3 (JPA)
POJO (Plain Old Java Object) Lze vytvářet pomocí new operátoru Testovatelné
Atributy třídy entity představují sloupce v databázi vazby na jiné entity
Operace (business logika) nad entitou by měly být vyjádřeny jako metody třídy entity Anti-vzor Anemic Entity (Fowler) - nedochůdče Nikoliv za každou cenu – pokud operace obnáší
interakce mezi více entitami, lépe řešit např. session EJB
Entita - příklad
Kontext perzistence
Promítání a načítání stavu entity z databáze je možné pouze pokud se entita nachází v kontextu perzistence (Persistence Context) – připojená entita (attached)
Mimo tento kontext je entita prostým objektem bez vazby na úložiště – odpojená entita (detached)
V kontextu jsou sledovány změny stavu entity stav je synchronizován se stavem v db synchronizace může být vyvolána explicitně či implicitně
má na starosti objekt EntityManager při uzavírání kontextu se všechny entity odpojí
Transakční kontext perzistence Doba života tohoto kontextu je pouze po dobu
trvání transakce často v rámci volání jedné metody klientem
V okamžiku ukončení transakce se uzavře i kontext všechny entity v kontextu se odpojí pouze pokud transakce proběhne v pořádku
(commit), změny v entitách se synchronizují z databází
Poznámka: platí pouze pro kontext řízený aplikačním serverem je možné vytvářet si vlastní kontext perzistence
Rozšířený kontext perzistence Doba života tohoto kontextu není
svázána s trváním transakce Všechny entity v kontextu zůstávají
připojeny i když je transakce ukončena Velmi užitečné v případech, kdy chceme
provádět delší konverzace s databází a zároveň se vyhnout dlouhým transakcím dlouhé transakce blokují "vzácné"
prostředky systému JDBC připojení, zámky
Rozšířený kontext - pseudokód
Entita coby přenosový objekt (TO) Odpojenou entitu lze použít jako přenosový objekt
lze ji serializovat a poslat na klienta klient může provést úpravy a odeslat ji zpět na server na serveru se musí provést tzv. merge
sloučení s verzí entity v kontextu (pokud v něm není, načte se)
vzor Transfer (Value) Object V případě složitějších entit může být problematické
přenášení celého grafu závislých entit může brzdit síť řešení: závislosti lze dohrávat dynamicky (lazy)
nevýhoda – v různých situacích je na klientovi entita s různě připojenými závislými entitami (NullPointerException)
Životní cyklus entity
Existuje v
paměti
Existuje v
paměti
Připojená
Připojená
Odpojená
Odpojená
Odstraněná
Odstraněná
Neexistuje
Neexistuje
garbage collector
odstranění z databáze
odstranění
- obnova stavu (refresh)- aktualizace stavu settery
merge
- vyčištění na kontextu- serializace
instanciace
- volání persist na EM- výsledek dotazu
Callback metody na entitách Během životního cyklu entity dochází ke
generování událostí Tyto události lze odchytávat přímo v entitě
prostřednictvím tzv. callback metod Události
vkládání (persisting) aktualizace (updating) mazání (deleting) výběr (selecting)
Všechny události mají Pre a Post callback metody výjimkou je výběr, který má pouze Post callback
12
Životní cyklus a callback metody
13
Existuje v
paměti
Existuje v
paměti
Připojená
Připojená
Odpojená
Odpojená
Odstraněná
Odstraněná
Neexistuje
Neexistuje
garbage collector
@PostRemove
@PreRemove
@PreUpdate a @PostUpdate, když jsou volány settery@PostLoad, když se provádí refresh
@PostLoad, když senahrává entita z DB
@PreUpdate, @PostUpdate,před a po volání UPDATEna databázi. Tj. pouze pokudje entita pozměněná.
@PrePersist@PostPersist
find() nebo JPQL
@PostLoad
Callback metody - seznam14
Anotace Popis označené metody
@PrePersist Volá se před vlastním provedením EntityManager::persist.
@PostPersist Volá se po uložení entity do databáze. Primární klíč je vygenerován a nastaven do svého atributu.
@PreUpdate Volá se před UPDATE operací. Důsledek volání setterů nebo EntityManager::merge.
@PostUpdate Volá se po provedení operace UPDATE nad databází.
@PreRemove Volá se před vlastním provedením EntityManager::remove.
@PostRemove Volá se po smazání entity z databáze.
@PostLoad Volá se po nahrání stavu z databáze do instance entity. Důsledek EntityManager::find, refresh a JPQL.
signatura: void nazevMetody()
Posluchači entit
Zpracování událostí v životním cyklu entit lze separovat do speciálních komponent – posluchačů Vhodné, když se logika v callback metodách přímo
nedotýká entity Posluchač je POJO s metodami označenými
anotacemi z tabulky na stránce 5 Signatura metody: void nazevMetody(Entita e) Posluchači se nasadí na třídu entity pomocí
anotace @EntityListeners
15
Posluchač PhotoLogger16
Konfigurace posluchače17
Pomocí anotace @EntityListeners
Alternativně v orm.xml. Vhodné pro ladění.
Generický posluchač entit
Není vázán na jediný typ entity Obdobné předchozímu typu posluchače Rozdíl v typu parametru callback metod
java.lang.Object Lze registrovat jako tzv. default entity
listener poslouchá na všech entitách možno pouze v orm.xml
18
Jednotka perzistence
Každá entita patří aspoň do jedné tzv. jednotky perzistence
Lze definovat více jednotek perzistence Každá pracuje s právě jedním datovým zdrojem
Entity lze přiřadit k jednotce explicitně či implicitně Implicitní zařazení entity
JPA provider skenuje JAR soubor a zkoumá anotace @Entity na třídách
Explicitní Entity lze pro každou jednotku vyjmenovat v souboru
META-INF/persistence.xml
Soubor persistence.xml
Obsahuje konfigurace jednotek perzistence v modulu
Modul může být obyčejný JAR nebo EJB-JAR Umístění v META-INF adresáři modulu JAR modul může být umístěn
na classpath běžného Java SE programu WEB-INF/lib v kořenovém adresáři enterprise archivu (.ear) v lib adresáři enterprise archivu
EJB-JAR se skenuje při umístění EAR na server
persistence.xml - příklad
Explicitní vyjmenováníentit patřících do jednotky BankTest
Implicitní zařazeníentit, tj. skenováníJAR souboru
Získání kontextu perzistence Nejsnadněji pomocí injektáže
Kontejner podává transakční perzistentní kontext
Pro rozšířený kontext je třeba nastavit atribut type anotace na hodnotu EXTENDED
Kontext lze získat také přes EntityManagerFactory
Poznámky k získávání kontextu Doporučuje se používat injektáž
vymyšleno pro zjednodušení práce nemusíme se starat o zavírání kontext nesmí se volat close()
Pokud se použije EntityManagerFactory programátor musí dbát na uzavírání získaného
kontextu voláním metody close() v prostředí Java SE se objekt továrny získá voláním
statické metody createEntityManagerFactory na třídě javax.persistence.Persistence
v Java EE injektáží do atributu anotovaného @PersistenceUnit
Práce s objektem EntityManager Ukládání Vyhledávání Aktualizace stavu Slučování Odstraňování Obnova stavu Uzamykání (v další přednášce)
Ukládání entit
Vkládání stavu entity do databáze Předpoklad, že entita doposud v databázi není
Vytvoří se nový objekt entity Nastaví se její vlastnosti a relace Zavolá se metoda EntityManager::persist(entita)
Po vložení se entita stává připojenou ke kontextu
Pokud má entita relace s jinými entitami, může systém vytvořit jejich reprezentaci v databázi společně s hlavní entitou Kaskádová politika musí být PERSIST
Ukládání entit
Při volání persist může být vložení do db (SQL INSERT) odloženo Pokud dojde k ukládání v rámci transakce, vložení
může být provedeno okamžitě, nebo na konci transakce ovládáno tzv. flush modem: setFlushMode(AUTO|
COMMIT) Mimo transakci lze vkládat pouze pokud je kontext
perzistence rozšířený Vlastní vložení je odloženo dokud se kontext nepřipojí k
transakci EntityManager::joinTransaction() injektovaný rozšířený kontext se připojuje automaticky
Vyhledávání entit Dva způsoby
podle primárního klíče vytvořením a provedením dotazu
Vyhledání podle primárního klíče – 2 metody <T> find(Class<T> entityClass, Objekt key)
snaží se vyhledat entitu podle zadaného primárního klíče pro číselné typy funguje autoboxing inicializuje vlastnosti entity podle lazy-loading politiky
<T> getReference(Class<T> entityClass, Objekt key) vrací objekt třídy T, ale pokud entita neexistuje, při prvním
přístupu k objektu se vyhazuje EntityNotFoundException tato výjimka se může vyhazovat již při volání getReference
Vyhledání entity dotazem
Vyhledání možné pomocí JPQL dotazu EntityManager nabízí tři typy metod pro
vytváření dotazu createQuery
sestrojí dotaz v syntaxi JPQL, který je předán jako parametr
createNamedQuery sestrojí dotaz podle připraveného výrazu v orm.xml
createNativeQuery sestrojí dotaz v nativní syntaxi SQL
V EJB 3.1 (JPA 2) nový nástroj: Criteria API vhodné pro sestavování dotazů za běhu
programu
Aktualizace entit
V době, kdy je entita připojená ke kontextu, lze na ní provádět úpravy Operace, které vracejí připojené entity
persist, find, getReference, vyhledání dotazem Ukládání do úložiště (SQL UPDATE) může
být prováděno automaticky (v závislosti na flush-mode)
Lze uložit explicitně voláním EntityManager::flush()
Slučování entit (merge)
Metoda EntityManager::merge(entita) Slučování odpojených entit s kontextem
Pokud entita ještě není v kontextu, je vytvořena plná kopie, která se připojí ke kontextu.
Pokud se již v kontextu nachází entita se stejným primárním klíčem, nahradí se její stav za stav odpojené entity
V obou případech metoda merge vrací připojenou entitu
Je-li kontext rozšířený, lze volat merge i mimo transakci
Odstraňování entit
Metoda EntityManager::remove(entita) Tato metoda nemusí okamžitě vyústit v
odstranění entity z databáze (tj. SQL DELETE) chování se odvíjí od nastavení flush-mode
Po volání remove je entita odpojena od kontextu
Má-li entita nějaké relace, mohou být také odstraněny v závislosti na kaskádové politice
Je-li kontext rozšířený, lze volat remove i mimo transakci
Obnova stavu entity
Metoda EntityManager::refresh(entita) V případě, že si nejsme jisti aktuálností
stavu připojené entity, lze zavolat refresh(entita) Přepíše všechny provedené změny stavem z db
Má-li entita nějaké relace, jejich stav může být také obnoven v závislosti na kaskádové politice
Je-li kontext rozšířený, lze volat refresh i mimo transakci
Metody contains a clear
Metoda contains(entita) vrací true, pokud kontext perzistence obsahuje entitu předanou jako parametr
Metoda clear() odpojí všechny entity momentálně připojené ke kontextu
Metoda flush
Entity manager rozhoduje, kdy se změny způsobené voláním persist, merge a remove promítnou do databáze
Synchronizaci lze prosadit voláním flush() Provádí se automaticky před voláním
dotazu, který souvisí se změnami v kontextu neúčinné implementace mohou provádět flush
před každým dotazem výjimkou je find, jelikož hledání podle
primárního klíč nemůže být ovlivněno změnami v kontextu
FlushModeType
Chování entity manageru lze ohledně synchronizace s databází řídit použitím výčtového typu FlushModeType AUTO
přednastavené chování, odpovídá popisu z předešlé stránky COMMIT
změny jsou synchronizovány v okamžiku ukončení transakce (commit)
synchronizace neprobíhá ani před dotazy používá se pro zvýšení výkonnosti (batch updates)
Nastavuje se metodou setFlushMode(mode) na EM
Mapování perzistentních objektů Párování tříd na tabulky, atributů entity na sloupce
a relace v databázi, generování prim. klíčů atp. Obvykle dvě cesty
Vytváříme schéma databáze podle objektového modelu
Vytváříme objektový model podle existujícího databázového schéma
JPA lze použít pro oba přístupy automatické generování databázového schéma automatické generování tříd entit ze schéma (nic moc) mapování pomocí anotací nebo xml
Základní mapovací prostředky @Table
Potřebujeme-li změnit defaultní mapování třídy entity na databázovou tabulku
Anotace se umísťuje na třídu entity Např.: @Table(name="ACCOUNT_TABLE")
@Column Popisuje mapování atributů entity na sloupce
tabulky Anotace se umisťuje na atribut třídy nebo na
příslušný getter Např.: @Column(name="DEPO") BigDecimal
deposit;
Mapování primárních klíčů
Každá entita musí mít primární klíč PK mohou být mapovány na jednu či více vlastností
primitivní typy, java.lang.String, složené s uvedených @Id
identifikuje jednu či více vlastností entity @GeneratedValue(strategy)
Doplněk k @Id, říká, že hodnota PK se bude generovat TABLE – hodnota PK je udržována ve speciální tabulce SEQUENCE – hodnota PK je generována sekvencí IDENTITY – bude použit sloupec typu IDENTITY AUTO – volba je ponechána na poskytovatel JPA (default)
Generování PK přes tabulku Programátorem definovaná tabulka, která v každé
řádce udržuje hodnotu pro daný PK Dva sloupce
PRIMARY_KEY_COLUMN – název primárního klíče VALUE_COLUMN – hodnota počítadla (hodnota PK)
Tato volba generování musí být doplněna o anotaci @TableGenerator – atributy:
name – název generátoru, odkazu z @GeneratedValue table – název db tabulky pkColumnName – název sloupce v tabulce pro názvy PK valueColumnName – název sloupce pro hodnoty PK pkColumnValue – název primárního klíče
TableGenerator - příklad
Generování PK přes sekvenci Některé DB mají speciální struktury pro
generování sekvencí (Oracle) @SequenceGenerator
doprovodná anotace k @GeneratedValue name – název generátoru pro odkazování sequence_name – název sekvence v DB initialValue – počáteční hodnota allocationSize – krok alokace
Generování přes sekvenci - příklad
Složené primární klíče
Někdy je zapotřebí, aby se PK skládal z více primitivních hodnot či řetězců
Složený klíč je reprezentován tzv. třídou PK tato třída je přiřazena k entitě anotací
@IdClass @IdClass(třída_pk)
Třída PK musí být serializovatelná musí veřejný no-arg konstruktor musí implementovat hash() a equals()
Entita se složeným primárním klíčem
Vyhledání podle složeného klíče:
Třída primárního klíče - příklad
Mapování vlastností entity
@Transient – označení neperzistentních vlastností
@Basic, FetchType – mapování primitivních typů
@Temporal – mapování časových vlastností @Lob – mapování objemných dat (BLOB,
CLOB) @Enumerated – mapování výčtových typů @ElementCollection – mapování kolekcí
primitivních typů a řetězců
Mapování neperzistentních vlastn. Někdy chceme mít ve třídě entity
vlastnost, kterou si nepřejeme ukládat do databáze
Označíme ji @Transient
Mapování primitivních typů
Mapování lze řídit anotací @Basic fetch – strategie načítání hodnoty; enum
FetchType LAZY – hodnota se nahraje při prvním přístupu EAGER – hodnota se nahraje při ihned
optional – pokud je true, sloupec je chápán jako nulovatelný (nemusí obsahovat žádnou hodnotu)
Mapování časových vlastností Časové vlastnosti lze mapovat do
sloupců typu date, time a timestamp By default se volí timestamp
@Temporal(type) enum TemporalType
DATE TIME TIMESTAMP
Lze použít spolu s @Basic pro zadání parametrů fetch a optional
Mapování objemných dat
JDBC definuje typy Blob a Clob pro objemná binární, resp. znaková data
Pomocí anotace @Lob lze mapovat vlastnosti entity na tyto typy pokud je typ vlastnosti char[], Character[]
nebo java.lang.String -> Clob pokud je typ byte[], Byte[], nebo
java.lang.Serializable -> Blob Anotaci lze kombinovat s @Basic
Mapování výčtových typů
Pomocí anotace @Enumerated lze mapovat vlastnosti, jejichž hodnota je výčtového typu @Enumerated(způsob) způsob je typu EnumType a může nabývat
hodnot ORDINAL – hodnota ukládána do DB jako číslo
(ordinál) STRING – hodnota ukládána do DB jako řetězec
Možno použít spolu s @Basic
Mapování kolekcí základních typů Od verze EJB 3.1 lze mapovat vlastnosti, jejichž
hodnota je kolekce základních typů, bez nutnosti vytvářet speciální entitu pro prvky kolekce.
@ElementCollection označuje vlastnost, která musí přiřaditelná typu
java.util.Collection<T> T musí být obalující třída primitivního typu nebo String atribut fetch určuje okamžik nahrání kolekce
@CollectionTable vyladění názvu a vlastností tabulky pro kolekce by default: název = název entity + vlastnost
Mapování mapy základních typů Podobně jako u kolekce základních typů, od
EJB 3.1 je možné mapovat mapy základních typů bez nutnosti vytvářet entitu pro dvojice v mapě
Znovu se použijí anotace @ElementCollection a @CollectionTable
Doprovodná anotace @MapKeyColumn určuje sloupec pro klíč mapy v tabulce pro dvojice
Anotace @Column určuje sloupec pro hodnotu dvojice v mapě
Mapování mapy - příklad
CLIENT_ID
CARD_TYPE CARD_NUMBER
1 MASTERCARD
7867 6768 6686 8777 7777
1 VISA 7777 9080 7773 2636 3883
Mapování entity na více tabulek Někdy je třeba mapovat jednu entitu na dvě
tabulky např. v důsledku vývoje nad převzatým modelem
Sekundární tabulku lze specifikovat anotací @SecondaryTable name – název sekundární tabulky pkJoinColumns – jeden či více sloupců v sekundární
sekundární tabulce pro spojovací primární klíč do hlavní tabulky. Hodnotou je sekvence @PrimaryKeyJoinColumn(name=<column_name>)
@Embedded objekty
JPA umožňuje navrhovat kompozitní entity, tj. entity, které obsahují jiné objekty, které sice nejsou entity, ale jejich vlastnosti jsou mapovány na tabulku hlavní entity.
Objekt komponenty je anotován @Emeddable Atribut hlavní entity, který drží komponentu je
anotován @Embedded @AttributeOverrides
obsahuje sekvenci @AttributeOverride – mapování vlastnosti komponenty na sloupec tabulky hlavní entity
Komponenta kompozitní entity
Kompozitní entita Client: