DPKOM_3 Perzistence v Javě 1
Obsah přednášky Java Persistence EntityManager Entity beans a POJO objekty Řízené versus neřízené entitní beany (entity) Pakování perzistentní jednotky (Packing Persistence Unit) Získání EntityManager Interakce s entitním manažérem Zdroje lokálních transakcí 2
Java Persistence Java Persistence je oddělený dokument specifikací od jádra specifikace EJB. Je to nejdůležitější inovace verze EJB 3.0. Specifikace Java Persistence: poskytuje standardní objektově relační mapování (integruje mnoho konceptů z Hibernate a JDO) není pouze svázaná s kontejnerem Java EE a může být testována a použita také v prostředích J2SE definuje rozhraní service provider, takže různí persistence providers mohou být použiti bez vlivu na kód entity 3
EntityManager Perzistence je klíčováčást platformy Java EE. EntityManager je ústřední služba pro všechny perzistentní akce přenos entitních informací do/z relační databáze. Entity jsou obyčejné javovské objekty, které jsou stejně alokovány. Nejsou perzistentní, dokud tak neučiní EntityManager. 4
EntityManager EntitníManagerřídí objektově relační mapování. API EntityManager poskytuje metody pro tři odlišné druhy operací: metody řízení životního cyklu entit metody synchronizace databázových operací metody pro vyhledání a dotazy na entity Dále poskytuje cachování a transakční služby. 5
Entity & session beany Entity mají klientem viditelnou perzistentní identitu (primární klíč), který se liší od jejich objektové reference. Entity mají perzistentní, klientem viditelné stavy. Entity nejsou vzdáleně přístupné (remotely accessible). Život entity může být kompletně nezávislý na životě aplikace (lifetime). 6
Entitní beany Příkladem je entita Customer. Customer cust = new Customer(); cust.setname( Bill ); Entita zůstane obyčejným objektem, dokud nepožádáme entitního mamažéra o její uložení do databáze. 7
import javax.persistence.*;.*; Poznámky import java.util.date; @Entity @Table(name Table(name="CUSTOMER_TABLE") public class Customer implements java.io.serializable { private int id; private String lastname; private String firstname; private CustomerType customertype; private Date timecreated = new Date(); private JPEG picture; @Id @GeneratedValue @Column(name Column(name="CUST_ID") public int getid() { return id; } public void setid(int pk) { id = pk; } public String getlastname() { return lastname; } public void setlastname(string lastname) { this.lastname = lastname; } 8
public String getfirstname() { return firstname; } public void setfirstname(string firstname) { this.firstname = firstname; } Poznámky @Enumerated Enumerated(EnumType EnumType.STRING) public CustomerType getcustomertype() { return customertype; } public void setcustomertype(customertype type) { customertype = type; } @Temporal Temporal(TemporalType TemporalType.TIME) public Date gettimecreated() { return timecreated; } public void settimecreated(date time) { timecreated = time; } } @Lob @Basic(fetch fetch=fetchtype FetchType.LAZY) public JPEG getpicture() { return picture; } public void setpicture(jpeg jpeg) { picture = jpeg; } 9
Perzistentní kontext Protože entity nemohou být zpřístupněny vzdáleně, je proto možné je rozmístit pouze lokálně a použít je buď z J2SE kódu mimo kontejner EJB, nebo z session beanů nebo zprávami řízených beanů z kontejneru EJB. Perzistentní kontext je spojení mezi vaší instancí v paměti a databází. Perzistentní kontext je manipulovatelný prostřednictvím API EntityManageru. 10
Perzistentní kontext Perzistentní kontext je množina řízených (managed) entitních instancí. EntityManager sleduje všechny entitní objekty uvnitř perzistentního kontextu kvůli změnám, aktualizacím v databázi s využitím pravidel flush modu. Poté co je perzistentní kontext uzavřený, všechny připojené entity (řízené) se stanou odpojenými a nejsou tedy dále řízeny EntityManagerem. 11
Perzistentní kontext Stav odpojených entitních objektů není synchronizován s databází. Existují dva typy perzistentních kontextů: 1. perzistentní kontext ohraničený transakcí Transaction-scoped persistence context 2. rozšířený perzistentní kontext Extended persistence context 12
Perzistentní kontext ohraničený transakcí Tento kontext žije stejně dlouho jako transakce a končí s jejím dokončením. Na konci je tento kontext zrušen a instance entit se stanou odpojenými. Pouze perzistentní kontexty řízené aplikačním serverem mohou být transakčně ohraničené. Jinými slovy pouze instance EntityManageru injektované prostřednictvím anotace @PersistenceContext nebo jejího XML ekvivalentu, mohou být transakčně ohraničené (omezené). 13
Poznámky @PersistenceContext(unitName PersistenceContext(unitName= titan titan ) EntityManager entitymanager; @TransactionAttribute(REQUIRED TransactionAttribute(REQUIRED) public Customer somemethod() { Customer cust = entitymanager.find(customer.class,, 1); cust.setname( new name ); return cust; } 14
Perzistentní kontext ohraničený transakcí Když má být prováděná metoda somemethod(), kontejner EJB ji vyvolá právě z kontextu JTA transakce (Java Transaction API). Odkaz na instanci entitního beanu Customer je získán z EntityManagera a metoda setname() změní jméno entity Customer. Instance beanu Customer bude řízena po celou dobu transakce. To znamená, že např. změny jména budou synchronizovány s databází. 15
Perzistentní kontext ohraničený transakcí Na konci metody je vrácen odkaz na instanci Customer. Po ukončení transakce je transakčně ohraničený kontext zničen a instance entity Customer již není dále řízena. Vyvolání metody setname() po ukončení transakce jinak neovlivní obsah databáze. Používá se u bezstavových session beanů. Např. metody openaccount(), deposit(), withdraw(), getbalance() vždy vytváří nový perzistentní kontext. 16
Rozšířený perzistentní kontext Rozšířený perzistentní kontext má delší životnost než transakce, využívá se u stavových session beanů. Instance entit, které jsou připojeny k rozšířenému perzistentnímu kontextu, jsou stále řízeny i po skončení transakce. Toto je zvláště užitečné v případech, kdy je třeba konverzovat delší dobu s databází, ale není žádoucí mít transakce běžící dlouhou dobu, protože transakce představují hodnotné zdroje jako třeba JDBC spojení a zámky databáze. Viz následující příklad: 17
Poznámky Customer cust = null; transaction.begin(); // začátek transakce 1 cust = extendedentitymanager.find(customer.class,, 1); transaction.commit(); // konec transakce 1 transaction.begin(); // začátek transakce 2 cust.setname( Bill Bill ); extendedentitymanager.flush(); // uložen ení změn do databáze transaction.commit(); // instance cust zůst stává připojena ipojena, změny jsou // uloženy do DB 18
Rozšířený perzistentní kontext V příkladu je lokální proměnná cust inicializována voláním metody find() a je stále řízena i po skončení transakce 1. 19
Životní cyklus entitních beanů persist() new new() refresh() managed remove() persist() removed merge() Persistence context ends detached 20
Životní cyklus entitních beanů new. Entitní instance byla vytvořena v paměti, atributy jsou naplňovány daty, ale není ještě asociovaná s perzistentní identitou v databázi nebo s perzistentním kontextem. (Změny stavů atributů entitní instance nejsou synchronizovány s databází). managed. Entita má perzistentní identitu v databázi a je aktuálně asociovaná s perzistentním kontextem. Je to stav po vyvolání metody persist(). 21
Životní cyklus entitních beanů detached (odpojena). Entita má perzistentní identitu, ale není nebo již dále není asociovaná s perzistentním kontextem. removed. Entita je aktuálně asociovaná s perzistentním kontextem, ale je naplánovaná pro odstranění z databáze. 22
Odpojené entity (Detached Entity) Zajímavá stránka odpojených entit je v tom, že mohou být serializované a poslané sítí vzdálenému klientu. Klient může nyní provést změny v instanci entity, a poslat instanci entity zpět serveru, aby mohla být opět synchronizována s databází (změny datových atributů jsou uloženy do databáze). 23
Pakování a instalace (rozmístění) entitních tříd Entitní třídy jsou pakovány a instalovány v perzistentních jednotkách (persistence unit). Perzistentní jednotka je logické seskupení entitních tříd, metadat mapování a konfiguračních dat pro databázi. Perzistentní jednotka je definovaná v souboru persistence.xml. Je to deployment deskriptor vyžadovaný specifikací Java Persistence. 24
Pakování perzistentní jednotka Packing a Persistence Unit Soubor persistence.xml definuje jednu nebo více perzistentních jednotek a je uložen v adresáři META-INF. Existují následující typy: obyčejný soubor JAR uvnitř classpath regulárního programu Java SE, soubor EJB-JAR. Perzistentní jednotka může být včleněna do rozmístění EJB. soubor JAR v adresáři WEB-INF/lib ve tvaru.war (web archive) soubor JAR v kořenu enterprise archive (.ear) soubor JAR v adresáři EAR lib. 25
Pakování perzistentní jednotka Packing a Persistence Unit Popisovač rozmístění persistence.xml definuje identitu a konfigurační vlastnosti pro každou perzistentní jednotku. Každá perzistentní jednotka musí mít identitu, i prázdný řetězec je platné jméno. Nejjednodušší příklad: <?xml version= 1.0 encoding= UTF-8?> <persistence xmlns=http://java.sun.com/xml/ns/persistence> <persistence-unit name= intro /> </persistence> 26
Pakování perzistentní jednotka Packing a Persistence Unit Každá persistentní jednotka je svázána pouze s jedním datovým zdrojem. V prostředí Java EE je tato asociace definovaná specifickým elementem XML. Kořen schéma XML persistence.xml je element <persistence>, který obsahuje jeden, nebo více elementů <persistence-unit>. Viz následující příklad. 27
Poznámky <persistence> <persistence-unit name="titan"> <jta jta-data data-source>java:/ source>java:/oracleds OracleDS</ </jta jta-data data-source> <properties> <property name="org.hibernate.hbm2ddl">update</property> </properties> </persistence-unit> </persistence> 28
Pakování perzistentní jednotka Packing a Persistence Unit Atribut name definuje jméno, podle kterého se na jednotku odkazujeme. Tento atribut je nutný a je používán injektovanými anotacemi a XML popisovači rozmístění. Atribut transaction-type, je volitelným atributem elementu <persistence-unit> a definuje, zda chceme, aby perzistentní jednotka byla řízena a integrována Java EE transakcemi (JTA), nebo používala lokální zdroj (RESOURCE_LOCAL) API javax.persistenceentitytransaction křízení integrity vašich instancí EntityManagerem. 29
Pakování perzistentní jednotka Packing a Persistence Unit Element <persistence-unit> má následující podelementy: <description> volitelný komentář popisující danou perzistentní jednotku <provider> volitelný element je plně kvalifikované jméno třídy nebo implementací rozhraní javax.persistence.persistenceprovider. Většinou nedefinujeme. 30
Pakování perzistentní jednotka Packing a Persistence Unit <JTA-data-source> volitelný definujete, pokud používáte: JTA nebo RESOURCE_LOCAL perzistentní jednotky. Tyto elementy určují specifickou identitu dodavatele konkrétního datového zdroje. Obyčejně je tento řetězec globálním jménem JNDI pro odkaz na datový zdroj. <maping-file> volitelný <jar-file> volitelný <class> volitelný 31
Pakování perzistentní jednotka Packing a Persistence Unit <properties> volitelný element definuje množinu atributů specifikovaných dodavatelem, předaných správci persistence. <exclude-unlisted-classes> volitelný 32
Perzistentní jednotka Pokud nejsou specifikována žádná jiná metadata uvnitř souboru persistence.xml, soubor JAR, který obsahuje persistence.xml, bude skenován od kořene po libovolnou třídu anotovanou anotací @javax.persistence.entity. Takto anotované třídy jsou přidány k množině tříd perzistentní jednotky. Je možné ještě přidat další soubory JAR, které chcete, aby byly také skenovány. Takové soubory se přidají do elementu <jar-file> 33
Poznámky 34 <persistence> <persistence> <persistence> <persistence> <persistence <persistence <persistence <persistence-unit name="titan"> unit name="titan"> unit name="titan"> unit name="titan"> <jta jta jta jta-data data data data-source>java:/ source>java:/ source>java:/ source>java:/oracleds OracleDS OracleDS OracleDS</ </ </ </jta jta jta jta-data data data data-source> source> source> source> <jar <jar <jar <jar-file>../lib/ file>../lib/ file>../lib/ file>../lib/customer.ja customer.ja customer.ja customer.jar</ </ </ </jat jat jat jat-file> file> file> file> <properties> <properties> <properties> <properties> <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property> </properties> </properties> </properties> </properties> </persistence </persistence </persistence </persistence-unit> unit> unit> unit> </persistence> </persistence> </persistence> </persistence>
Perzistentní jednotka Skenování souborů JAR je garantováno v prostředí Java EE a nemělo by být problémem v prostředí Java SE. V každém případě je možné třídy deklarovat explicitně s použitím elementu <class>: 35
Poznámky 36 <persistence> <persistence> <persistence> <persistence> <persistence <persistence <persistence <persistence-unit name="titan"> unit name="titan"> unit name="titan"> unit name="titan"> <jta jta jta jta-data data data data-source>java:/ source>java:/ source>java:/ source>java:/oracleds OracleDS OracleDS OracleDS</ </ </ </jta jta jta jta-data data data data-source> source> source> source> <class> <class> <class> <class>com.titan.domain.cabin com.titan.domain.cabin com.titan.domain.cabin com.titan.domain.cabin</class> </class> </class> </class> <class> <class> <class> <class>com.titan.domain.customer com.titan.domain.customer com.titan.domain.customer com.titan.domain.customer</class> </class> </class> </class> <properties> <properties> <properties> <properties> <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property> </properties> </properties> </properties> </properties> </persistence </persistence </persistence </persistence-unit> unit> unit> unit> </persistence> </persistence> </persistence> </persistence>
Perzistentní jednotka Třídy Cabin a Customer jsou přidány do množiny perzistentní jednotky spolu s ostatními třídy získanými z archivní jednotky. Pokud nechceme, aby byl skenován soubor JAR persistence.xml, pak se použije element <excluded-unlisted-classes> 37
Poznámky 38 <persistence> <persistence> <persistence> <persistence> <persistence <persistence <persistence <persistence-unit name="titan"> unit name="titan"> unit name="titan"> unit name="titan"> <jta jta jta jta-data data data data-source>java:/ source>java:/ source>java:/ source>java:/oracleds OracleDS OracleDS OracleDS</ </ </ </jta jta jta jta-data data data data-source> source> source> source> <class> <class> <class> <class>com.titan.domain.cabin com.titan.domain.cabin com.titan.domain.cabin com.titan.domain.cabin</class> </class> </class> </class> <class> <class> <class> <class>com.titan.domain.customer com.titan.domain.customer com.titan.domain.customer com.titan.domain.customer</class> </class> </class> </class> <excluded <excluded <excluded <excluded-unlisted unlisted unlisted unlisted-classes/> classes/> classes/> classes/> <properties> <properties> <properties> <properties> <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property <property name="org.hibernate.hbm2ddl">update</property> </properties> </properties> </properties> </properties> </persistence </persistence </persistence </persistence-unit> unit> unit> unit> </persistence> </persistence> </persistence> </persistence>
Získání EntityManageru V Javě SE jsou instance Entitních Managerů vytvářeny pomocí @javax.persistence.entitymanagerfactory Java EE je možné také použít rozhraní factory, ale Java EE poskytuje některé další možnosti k získání instancí je snadnější. 39
package javax.persistence; public interface EntityManagerFactory { EntityManager createentitymanager(); EntityManager createentitymanager(java.util.map map); // pro další rozší šířen ení specifikací persistence.xml void close(); boolean isopen(); } Poznámky EntityManager- Factory 40
Poznámky public class Persistence { public static EntityManagerFactory createentitymanagerfactory( String unitname ); public static EntityManagerFactory createentitymanagerfactory( String unitname, java.util.map properties; ); EntityManager- Factory v Javě SE 41
EntityManager-Factory Javě SE Třída javax.persistence.persistence vyhledá popisovač rozmístění persistence.xml podle unitname. To umožní lokalizovat EntityManagerFactory, která odpovídá danému jménu. 42
EntityManagerFactory Javě EE V Javě EE získání instancí může být přímo injektováno do položky nebo metody set() pomocí anotace @javax.persistence.persistenceunit package javax.persistence; } @Target({METHOD, FIELD, TYPE})@Retention(RUNTIME) public @interface PersistenceUnit { String name() default ; String unitname() default ; 43
EntityManagerFactory Při použití PersistenceUnit ta nejen injektuje EntityManagerFactory, ale také registruje odkaz na ni uvnitř JNDI ENC v EJB. Kontejner EJB je zodpovědný označení anotace @PersistenceUnit a injektování odpovídající factory viz následující kód: 44
Poznámky import javax.persistence.*;.*; import javax.ejb.*.* ; @Stateless public MyBean implements MyBusinessInterface { @PersistenceUnit(unitName PersistenceUnit(unitName= CRM CRM ) private EntityManagerFactory factory; private EntityManagerFactory factory2; } @PersistenceUnit(unitName PersistenceUnit(unitName= CUSTDB CUSTDB ) public void setfactory2(entitymanagerfactory f) { this.factory2 = f; 45
EntityManagerFactory Když je vytvořena instance bezstavového beanu, kontejner EJB nastaví datový atribut factory na CRM, definované v persistence unit. Také volá setfactory2() s persistence unit CUSTDB. V prostředí Java EE není třeba volat metodu close(). 46
Získání perzistentního kontextu. Perzistentní kontext může být vytvořen voláním EntityManagerFactory.createEntityManager(). Vrácená instance reprezentuje rozšířený perzistentní kontext. Je-li v EntityManagerFactory nastaveno JTAenable, pak je možné explicitně získat instanci EntityManager uvnitř transakce voláním metody EntityManager.joinTransaction(). Pokud nezískáte EntityManager uvnitř transakce, potom změny provedené v entitách nejsou synchronizovány s obsahem databáze. 47
Získání perzistentního kontextu. Použití API EntityManagerFactory je trochu upovídané a může být těžkopádné při vnořené EJB volání. Naštěstí EJB a specifikace Java Persistence jsou výborně integrované. EntityManager může být přímo injektovaný do EJB použitím anotace. @javax.persistence.persistencecontext (jako ekvivalent XML). 48
package javax.persistence; Poznámky public enum PersistenceContextType { TRANSACTION, EXTENDED } public @interface PersistenceProperty { String name(); String value(); } @Target{METHOD Target{METHOD, TYPE, FIELD}) @Retention(RUNTIME@ Retention(RUNTIME) public @interface PersistenceContext { String name() default ; String unitname() default ; PersistenceContextType type() default TRANSACTION; PersistenceProperty[] properties() default {}; } 49
Získání perzistentního kontextu. Anotace @PersistentContext funguje víceméně stejným způsobem jako @PersistenceUnit kromě toho, že místo instance EntityManagerFactory je injektovaná instance entitního manažera: @Stateless public class MySessionBean implements MySessioinRemote { @PersistenceContext(unitName= titan ) private EntityManager entitymanager;... } 50
Dependency injection Je to výkonný mechanismus pro získání referencí na zdroje a pro injektování referencí objektům v relaci s EJB. Injection je technika spolehnutí se na kontejner, který poskytne ovladače k objektům ke kterým má přístup. Dříve bylo třeba zdroje vyhledávat pomocí JNDI. Nyní pouze definujeme reference a používáme objekty. Kontejner injektuje reference před vašim voláním metod. 51
Získání perzistentního kontextu. Atribut unitname() identifikuje perzistenci. Perzistentní kontext ohraničený transakcí je defaultně injektovaný, když se používá tato anotace. Je možné zastínit (předefinovat) default s atributem type(). Když zpřístupníme tento transakcí omezený EntityManager, perzistentní kontext bude asociovaný s transakcí, dokud neskončí. To znamená, že pokud jste v interakci s entitními managery uvnitř kontextu transakce, nezáleží na tom, zda to jsou odlišné instance, které jsou injektovány do různých beanů. Bude použit stejný perzistentní kontext. 52
Získání perzistentního kontextu. EXTENDED entitní manager může být použit jen pro stavové session beany. @Stateful public class MyStatefulBean implements MyStatefulRemote { @PersistenceContext(unitName= titan, type=persistencecontexttype.extended) private EntityManager manager ;... } Když je vytvořen MyStatefulBean, je vytvořen také perzistentní kontext pro injektovaný atribut manager. Perzistentní kontext má stejnou životnost jako bean. Když je stavový session bean odstraněn, perzistentní kontext je uzavřen. 53
package javax.persistence; public interface EntityManager { public void persist(object entity); public <T> T find(class <T> entityclass, Object primarykey); public <T> T getreference(class <T> entityclass, Object primarykey); public <T> T merge(t entity); public void remove(object entity) ; public void lock(object entity, LockModeType lockmode); public void getreference(object entity); public Boolean contains(object entity); public void clear(); public void jointransaction(); public void flush(); public FlushModeType getflushmode(); public void setflushmode(flushmodetype type); Poznámky Interakce s entitním managerem Existuje bohaté dotazovací API, ke kterému je možné přistupovat vytvořením dotazovacích objektů z konkrétních metod EntityManageru } public Query createquery(string querystring); public Query createnamedquery(string name): public Query createnativequery(string sqlstring); public Query createnativequery(string sqlstring, String resultsetmaping); public Query createnativequery(string sqlstring, Class resultclass); public Object getdelegate(); public void close(); public Boolean isopen(); 54
Perzistentní entity Učinit entity perzistentní znamená v terminologii EJB jejich vložení do databáze. K vytvoření entity je třeba nejdříve alokovat paměť pro její instanci (metoda new()), nastavit datové atributy a propojit relace, který může mít instance s dalšími objekty (stejné jako v Javě). Pak je třeba vyvolat metodu persist() EntityManageru. Customer cust = new Customer(); cust.setname( Bill ); entitymanager.persist(cust); 55
Perzistentní entity Po vyvolání metody, zařadí EntityManager instanci do fronty na zapsání do databáze. Skutečné vložení instance do databáze je závislé na několika věcech. Je-li metoda persist() vyvolaná uvnitř transakce, je vložení vykonáno ihned, nebo na konci vlastní transakce závisí na tzv. flush módu (kdy se provádí konkrétní zápisy). Zápis může být vyvolán uvnitř transakce manuálně, vyvoláním metody flush(). 56
Vyhledání entit v databázi Při volání metody persist() mimo transakci, (pouze v rozšířeném perzistentním kontextu), zápis instance do databáze se uloží do fronty požadavků a provede se teprve až se perzistentní kontext asociuje s transakcí. EntityManager nabízí dvě možnosti vyhledání: 1. Vyhledání entity pomocí zadaného primárního klíče. 2. Vyhledání entit pomocí dotazu (executing query). 57
Metody find() a getreference() hledání podle primárního klíče EntityManager má dvě metody na vyhledání entit pomocí primárního klíče: public interface EntityManager { } <T> T find(class<t> entityclass, Object primarykey); <T> T getreference(class>t> entityclass, Object primarykey); Obě metody mají stejné argumenty entitní třídu a primární klíč. Java využívá parametrizované třídy (generics) a proto není třeba provádět přetypování (casting). 58
Metody find() a getreference() hledání podle primárního klíče Metoda find() vrací null, pokud se entita v databázi nenašla. Také inicializuje stav, založený na politice lazy-loading, pro každý datový atribut (lazy-loading: entita není dodána jako celek, ale podle požadovaných datových atributů vlastností). Customer cust = entitymanager.find( Customer.class, 2); primitivní typ 2 int je automaticky převeden na Integer, to z důvodu, pokud by metoda find() očekávala parametr typu Object 59
Metody find() a getreference() hledání podle primárního klíče Customer cust = null; try { cust = entitymanager.getreference(customer.class, 2); } catch (EntityNotFoundException notfound) { // obnoveni logiky } Metoda getreference() se liší od předchozí metody při nenalezení entity v databázi. Metoda v tomto případě vyhazuje výjimku javax.persistence.entitynotfoundexception. Obě metody mohou být vyvolány mimo transakci, ale v tom případě pouze v rozšířeném perzistentním kontextu. 60
Dotazy queries Pro dotazy je použito EJB QL a metody createquery(), createnamedquery() a createnativequery(). Query objekt se vytvoří vyvoláním uvedených metod patřících EntityManageru. public interface EntityManager { } Query createquery(string querystring); Query createnamedquery(string name); Query createnativeqyery(string sqlstring); Query createnativequery(string sqlstring, Class resultclass); Query createnativequery(string sqlstring, String resultsetmaping); 61
Dotazy queries Vytváření a provádění EJB QL dotazů je analogické vytváření s spouštění JDBC příkazů: Query query = entitymanager.createquery( from Customer c where id=2 ); Customer cust = (Customer)query.getSimpleResult(); Všechny instance vrácené uvedenými třemi metodami zůstávajířízenými (managed) po dobu aktivity perzistentního kontextu vrámci něhož byly zpřístupněny. To znamená, že další volání metod vrátí stejné entitní objekty. 62
Aktualizace entit updating Aktualizaci entity je možné provést po jejím vyhledání metody find(), getreference() nebo provedením dotazu (query), v době, kdy je entita řízena perzistentním kontextem (tento perzistentní kontext není uzavřen). Čas konkrétní aktualizace je závislý na metodě flush(), nebo můžete vyvolat flush() přímo. @PersistenceContext EntityManager entitymanager; @TransactionAttribute(REQUIRED) public void updatebedcount(int id, int newcoint) { Cabin cabin = entitymanager.find(cabin.class, id); cabin.setbedcount(newcount); } 63
Opětovné vkládání entit merging entities Specifikace Java Persistence dovoluje opět uložit změny datových atributů entity, která byla odpojena do databáze. Změny většinou provedl vzdálený klient. Činnost ukážeme na příkladě, kde klient volá metodu vzdáleného session beanu TravelAgent k nalezení instance cabin v databázi: 64
Poznámky @PersistenceContext EntityManager entitymanager; @TransactionAttribute(REQUIRED TransactionAttribute(REQUIRED) public Cabin findcabin(int id) { return entitymanager.find(cabin.class,, id); } 65
Opětovné vkládání entit merging entities V uvedeném příkladě perzistentní kontext končí s ukončením metody findcabin(), protože se jedná o jednoduchou JTA transakci. Když je instance entity Cabin serializovaná, je odpojena od entity manageru a poslána vzdálenému klientovi. Klient může provést změny a zpět poslat instanci na server pro uložení do databáze. Následuje kód vzdáleného klienta: Cabin cabin = travelagent.findcabin(1); cabin.setbencount(4); travelagent.updatecabin(cabin); 66
Opětovné vkládání entit merging entities Metoda updatecabin() vezme parametr a sloučí entitní instanci zpět v aktuálním perzistentním kontextu entitního manageru voláním metody merge(): @PersistenceContext EntityManager entitymanager; @TransactionAttribute(REQUIRED) public void updatecabin(cabin cabin) { Cabin copy = entitymanager.merge(cabin); } 67
Opětovné vkládání entit merging entities Změny, které provedl vzdálený klient nyní budou provedeny v databázi. Mohou nastat dvě alternativy: 1. Entitní manager již nepracuje s instancí beanu Cabin se stejným ID. Pak je vytvořena plná kopie parametru cabin a vrácena z metody merge(). Tuto kopii pak řídí entitní manager a změny v databázi budou provedeny v závislosti na metodě flush(). Parametr cabin zůstane nepřipojen a neřízen. 68
Opětovné vkládání entit merging entities 2. Pokud entitní manager pracuje s instancí paramentu cabin se stejným primárním klíčem, potom obsah parametru cabin je zkopírován do řízeného objektu instance. Metoda merge() vrací řízenou instanci. Parametr cabin zůstane nepřipojen a neřízen. 69
Odstraňování entit removing entities Entita může být odstraněna voláním EntityManager.remove(). Skutečné odstranění je závislé na metodě flush(). @PersistenceContext EntityManager entitymanager; @TransactionAttributes(REQUIRED) public void removecabin(int id) { Cabin cabin = entitymanager.find(cabin.class, id); entitymanager.remove(cabin); } 70
Odstraňování entit removing entities Po vyvolání metody remove() je instance cabin již neřízena a bude odpojena. Její možné vazby na další objekty mohou být součástí kaskádního odstranění objektů. Pokud by bylo třeba opět obnovit zrušenou instanci cabin, je třeba použít metodu persist(). 71
Metoda refresh() Tato metoda se používá k aktualizaci právě zpracovávané entity vzhledem k databázi (podobně jako aktualizace internetového prohlížeče). Instance má změněné datové atributy podle databáze. @PersistenceContext EntityManager entitymanager; @TransactionAttributes(REQUIRED) public void removecabin(int id) { Cabin cabin = entitymanager.find(cabin.class, id) ; entitymanager.refresh(cabin); } 72
Metody contains() a clear() Metoda contains() vezme jako parametr instanci entity. Je-li tato instance aktuálněřízena perzistentním kontextem, metoda vrací true. Jestli potřebujete odpojit všechny instance řízených entit od perzistentního kontextu, můžete vyvolat metodu clear() entitního manageru. Všechny provedené změny v entitních instancích se však ztratí. Proto je doporučeno nejdříve provést metodu flush() a následně pak metodu clear(). 73
Metoda flush() a FlushModeType Všechny změny v databázi se provedou, až EntityManager vykoná metodu flush(). Je samozřejmě možné explicitní vyvolání metody. Standardně je metoda flush() vyvolávaná automaticky před query a v době ukončování transakce. Změnu tohoto chování je možnéřídit pomocí výčtové třídy javax.persistence.flushmodetype: public enum FlushModeType { AUTO, COMMIT } 74
Metoda flush() a FlushModeType Auto je defaultní chování popsané dříve. COMMIT znamená, že se změny provádí až se skončením transakce, tedy ne před query (dotazem). 75
Zdroje lokálních transakcí Perzistentní kontext Entitního Managera je obyčejněřízen pomocí JTA transakcí (v prostředí Java EE). Při běhu v jiných prostředích než Java EE, není dostupná JTA, takže specifikace Java Persistence API poskytuje podobné API prostřednictvím rozhraní EntityTransaction. Přístup k EntityTransaction lze získat pomocí operace EntityManager.getTransaction(). 76
Zdroje lokálních transakcí public interface EntityTransaction { } public void begin(); public void commit(); public void rollback(); public boolean isactive(); metoda begin() vyhazuje IllegalStateException jeli již EntityTransaction aktivní. metody commit() a rollback() vyhazují IllegalStateException když není aktivní transakce. 77
Zdroje lokálních transakcí EntityTransactions není možné použít, pokud transakční typ perzistentní jednotky není JTA. Ukázka předchozích příkladů (kapitola 4) převedených jako javovské samostatné (standalone) aplikace s použitím API javax.persistence.persistence a EntityTransaction: 78
import javax.persistence..persistence.*; import java.util util.hashmap HashMap; Poznámky import com.titan..titan.domain domain.cabin Cabin; public class StandaloneClient { public static void main(string String[] args) throws Exception { HashMap map = new HashMap(); EntityManagerFactory factory = Persistence.createEntityManagerFactory createentitymanagerfactory("titan", map); EntityManager manager = factory.createentitymanager createentitymanager(); try { createcabin(manager); Cabin cabin_2 = manager.find find(cabin Cabin.class class, 1); System.out out.println println(cabin cabin_2. _2.getName getname()); System.out out.println println(cabin cabin_2. _2.getDeckLevel getdecklevel()); System.out out.println println(cabin cabin_2. _2.getShipId getshipid()); System.out out.println println(cabin cabin_2. _2.getBedCount getbedcount()); } finally { manager.close close(); factory.close close(); } } 79
Poznámky public static void createcabin(entitymanager manager) { Cabin cabin_1 = new Cabin(); cabin_1. _1.setId setid(1); cabin_1. _1.setName setname("master Suite"); cabin_1. _1.setDeckLevel setdecklevel(1); cabin_1. _1.setShipId setshipid(1); cabin_1. _1.setBedCount setbedcount(3); } } EntityTransaction transaction = manager.gettransaction gettransaction(); transaction.begin begin(); manager.persist persist(cabin cabin_1); transaction.commit commit(); 80
Zdroje lokálních transakcí Nejdříve musíme získat odkaz na EntityManagerFactory, který reprezentuje perzistentní jednotku. Použijeme třídu javax.persistence.persistence k nalezení perzistentní jednotky titan prostřednictvím statické metody createentitymanagerfactory. Když je nalezena factory, vytvoříme instanci od EntityManageru s níž jsme pak v interakci. 81
Zdroje lokálních transakcí Metoda createcabin() získá instanci EntityManageru jako parametr. K tomu, aby se uložila nová entita Cabin do databáze, potřebujeme být v interakci s entitním managerem v transakční jednotce. Protože aplikace běží mimo aplikačního serveru, nemůžeme použít JTA (Java Transaction API) ale musíme použít místo toho API EntityTransaction k započetí a ukončení práce. 82
Zdroje lokálních transakcí Je to velmi podobné jako s operacemi využívajícími JDBC. Při práci s JDBC obdržíme od datového zdroje java.sql.connection, podobně jako jsme obdrželi EntityManager z EntityManagerFactory. Pak použijeme metody java.sql.connection commit() a rollback() k ukončení naší práce stejně jako to děláme v příkladě s EntityTransaction. 83