EJB 3.0 - rychlokurz
Stručné shrnutí zejména syntaktických prvků použitých v EJB 3.0. V podstatě je stejně potřeba si přečíst specifikaci nebo nějakou tlustou knihu, tohle je jen takový přehled vlastností.
Specifikace | Javadoc
SessionBean
Vytvořeno v EJB modulu (tj. v eclipse EJB project). Potřebuje dvě věci - interface a implementaci (třídu). Interface používá buď anotaci javax.ejb.Local nebo javax.ejb.Remote. Implementace buď anotaci javax.ejb.Stateless nebo javax.ejb.Stateful. Příklad:
Entity
Oproti EJB 2 se používá Java Persistence API (JPA). Entity mohou být umístěny v samostatném obyčejném javovém projektu. Entitu reprezentuje jedna třída s anotací javax.persistence.Entity(name="NazevEntity"), kde název entity je unikátní v rámci persistence unit (jeden kontext). Má jeden povinný bezparametrový public konstruktor a případné další. Nesmí být final. Instanční proměnné private/protected/default + getter a setter (do getterů a setterů není vhodné dávat business logiku, není zaručeno pořadí volání).
- Field based access - anotace na fieldech
- Property based access - anotace na getterech
Vhodné řešení - anotace na fieldech a v entitě pouze getVo, updateFromVo, takže uživatelé entity nemohou přímo na položky. V těchto dvou metodách pak lze dělat nějaké transformace z DB uložení do civilizovanějšího uložení v javě.
Anotace pro entitu:
- Entity - označení třídy za entitu, definice jejího jména
- Table - definice jména databázové tabulky
- NamedQuery, NamedQueries - EJB QL dotazy
Anotace pro fieldy:
- Id - primární klíč, složený pak s využitím nějakého VO/beanu
- Column - sloupeček, atributy name, length aj. Viz javadoc.
- Transient, pokud to není persistentní atribut
- Enumeration - umožňuje použít enum přímo jako field, tj. programátor nemusí dělat konverzi
- Temporal - potřeba pro datumové fieldy
Typy: primitivní, String, BigInteger, BigDecimal, java.util.Date, Calendar, java.sql.Date/time/Timestamp, user-defined serializable bean, byte[], char[], enum aj.
Anotací a možností u entit je tolik, že je to mimo možnosti tohoto textu, viz javadoc.
Reference
Lookupem v jndi kontextu nebo pomocí tzv. injektování referencí (dependency injector).
Reference na session bean:
Reference na datasource (definovaný na aplikačním serveru):
Reference na JMS Queue (definovanou na aplikačním serveru, obdobně factory):
Transakce
Na implementaci session beanu nebo metodě v implementaci anotace javax.ejb.TransactionAttribute(TransactionAttributeType.xxx)
Entity Manager
Zásadní vtip - je tu jakýsi PersistenceContext, což je v podstatě cache objektů - pracuje se s lokálními objekty a občas dochází k synchronizaci s databází, což může vést k problémům - práce s daty, která jsou zastaralá.
Referenci na EntityManager lze získat následovně:
- persist(entita) - vytvoření nové entity, tj. zanesení do kontextu
- merge(entita) - update, dělá se automaticky na konci transakce, synchronizuje mezi transakcemi v rámci kontextu
- remove(entity) - smaže entitu z kontextu
- refresh(entita) - načte znovu z databáze, tj. přepíše cache v kontextu
- flush() - synchronizuje kontext s databází
- find(Class, primaryKey) - pokusí se najít entitu a začít spravovat v kontextu, pokud nenajde, vrátí null
- getReference(Class, primaryKey) - pokud nenajde, vyhodí EntityNotFoundException, jinak vrací referenci, tj. probíhá zde tzv. lazy loading
NamedQueries
U entity lze zadefinovat dotazy:
- query - dotaz v EJB QL. V dotazu musí být ve FROM zaveden alias, který je pak v rámci query využíván. Název tabulky je fakticky název entity, převod na jméno tabulky probíhá později. Parametry buď ?1, ?2, nebo :nazevArg1, :nazev2, pak lze volat query.setParameter(1,xxx) nebo query.setParameter("nazevArg1", xxx)
Instanci dotazu pak lze získat pomocí em.createNamedQuery("název") a voláním query.getSingleResult() nebo query.getResultList() získat data. Single result háže případně NoResultException nebo NonUniqueResultException.
Native Queries
Entity Manager navíc umožňuje použít tzv. native query, tj. query psané pro specifickou databázi. Např. jsem toto použil, když jsem chtěl udělat FOR UPDATE na postgresql. Native query podporuje binding parametrů pomocí ?1, ?2 a zdá se, že i bez indexů a pak je index dán pořadím v dotazu. U postgresql jsem narazil na problém, že jsem měl v entitě definovány sloupečky velkými písmeny, ale postgresql vrací malá písmena a pole se pak nenamapují (něco ve smyslu "The primary key read from the row during the execution of the query was detected to be null"). Velmi dobré je, že lze metodě createNativeQuery předat i třídu, kterou entita má, takže funguje vlastně ve výsledku stejně jako např. named query.
SessionBean
Vytvořeno v EJB modulu (tj. v eclipse EJB project). Potřebuje dvě věci - interface a implementaci (třídu). Interface používá buď anotaci javax.ejb.Local nebo javax.ejb.Remote. Implementace buď anotaci javax.ejb.Stateless nebo javax.ejb.Stateful. Příklad:
@javax.ejb.Local
public interface DocumentManager {...}
@javax.ejb.Stateless(name = "DocumentManager",
mappedName = "session/DocumentManager")
public class DocumentManagerBean
implements session.ejb.DocumentManager {...}
Entity
Oproti EJB 2 se používá Java Persistence API (JPA). Entity mohou být umístěny v samostatném obyčejném javovém projektu. Entitu reprezentuje jedna třída s anotací javax.persistence.Entity(name="NazevEntity"), kde název entity je unikátní v rámci persistence unit (jeden kontext). Má jeden povinný bezparametrový public konstruktor a případné další. Nesmí být final. Instanční proměnné private/protected/default + getter a setter (do getterů a setterů není vhodné dávat business logiku, není zaručeno pořadí volání).
- Field based access - anotace na fieldech
- Property based access - anotace na getterech
Vhodné řešení - anotace na fieldech a v entitě pouze getVo, updateFromVo, takže uživatelé entity nemohou přímo na položky. V těchto dvou metodách pak lze dělat nějaké transformace z DB uložení do civilizovanějšího uložení v javě.
Anotace pro entitu:
- Entity - označení třídy za entitu, definice jejího jména
- Table - definice jména databázové tabulky
- NamedQuery, NamedQueries - EJB QL dotazy
Anotace pro fieldy:
- Id - primární klíč, složený pak s využitím nějakého VO/beanu
- Column - sloupeček, atributy name, length aj. Viz javadoc.
- Transient, pokud to není persistentní atribut
- Enumeration - umožňuje použít enum přímo jako field, tj. programátor nemusí dělat konverzi
- Temporal - potřeba pro datumové fieldy
Typy: primitivní, String, BigInteger, BigDecimal, java.util.Date, Calendar, java.sql.Date/time/Timestamp, user-defined serializable bean, byte[], char[], enum aj.
Anotací a možností u entit je tolik, že je to mimo možnosti tohoto textu, viz javadoc.
Reference
Lookupem v jndi kontextu nebo pomocí tzv. injektování referencí (dependency injector).
Reference na session bean:
@javax.ejb.EJB(mappedName = "session/DocumentManager")
private session.ejb.DocumentManager docMgr;
Reference na datasource (definovaný na aplikačním serveru):
@javax.annotation.Resource(name = "jdbc/Datasource")
private javax.sql.DataSource dataSource;
Reference na JMS Queue (definovanou na aplikačním serveru, obdobně factory):
@javax.annotation.Resource(name="/jms/Queue", mappedName="jms/Queue" )
javax.jms.Queue queue;
Transakce
Na implementaci session beanu nebo metodě v implementaci anotace javax.ejb.TransactionAttribute(TransactionAttributeType.xxx)
Entity Manager
Zásadní vtip - je tu jakýsi PersistenceContext, což je v podstatě cache objektů - pracuje se s lokálními objekty a občas dochází k synchronizaci s databází, což může vést k problémům - práce s daty, která jsou zastaralá.
Referenci na EntityManager lze získat následovně:
@javax.persistence.PersistenceContextK práci s daty v kontextu jsou následující metody
private javax.persistence.EntityManager em;
- persist(entita) - vytvoření nové entity, tj. zanesení do kontextu
- merge(entita) - update, dělá se automaticky na konci transakce, synchronizuje mezi transakcemi v rámci kontextu
- remove(entity) - smaže entitu z kontextu
- refresh(entita) - načte znovu z databáze, tj. přepíše cache v kontextu
- flush() - synchronizuje kontext s databází
- find(Class, primaryKey) - pokusí se najít entitu a začít spravovat v kontextu, pokud nenajde, vrátí null
- getReference(Class, primaryKey) - pokud nenajde, vyhodí EntityNotFoundException, jinak vrací referenci, tj. probíhá zde tzv. lazy loading
NamedQueries
U entity lze zadefinovat dotazy:
@javax.persistence.NamedQueries(value = {
@javax.persistence.NamedQuery(name = "Country.findAll",
query = "SELECT c FROM Country c")
})
- name - notace je NazevEntity.nazevDotazu, název je globální v rámci persistence unit (= jeden entity manager)- query - dotaz v EJB QL. V dotazu musí být ve FROM zaveden alias, který je pak v rámci query využíván. Název tabulky je fakticky název entity, převod na jméno tabulky probíhá později. Parametry buď ?1, ?2, nebo :nazevArg1, :nazev2, pak lze volat query.setParameter(1,xxx) nebo query.setParameter("nazevArg1", xxx)
Instanci dotazu pak lze získat pomocí em.createNamedQuery("název") a voláním query.getSingleResult() nebo query.getResultList() získat data. Single result háže případně NoResultException nebo NonUniqueResultException.
Native Queries
Entity Manager navíc umožňuje použít tzv. native query, tj. query psané pro specifickou databázi. Např. jsem toto použil, když jsem chtěl udělat FOR UPDATE na postgresql. Native query podporuje binding parametrů pomocí ?1, ?2 a zdá se, že i bez indexů a pak je index dán pořadím v dotazu. U postgresql jsem narazil na problém, že jsem měl v entitě definovány sloupečky velkými písmeny, ale postgresql vrací malá písmena a pole se pak nenamapují (něco ve smyslu "The primary key read from the row during the execution of the query was detected to be null"). Velmi dobré je, že lze metodě createNativeQuery předat i třídu, kterou entita má, takže funguje vlastně ve výsledku stejně jako např. named query.
Kategorie: Programování.