PA165: Persistence Layer Petr Adámek Content: Persistence I. • Introduction to data persistence – Where to store data – How to work with data (Persistence technologies in Java EE) – Architecture of data persistence layer • Introduction to ORM – What is ORM – Basic Principles • JPA – Introduction – Entities in JPA – JPA Components – Entity Lifecycle 2PA165: Data Persistence I Content: Persistence II • JPA – Advanced Mapping – Querying • JPQL • Criteria API • Alternatives – EJB 2.x – JDO – JDBC – Embedded SQL – Spring JDBC – iBatis • Best practices 3PA165: Data Persistence I INTRODUCTION INTO DATA PERSISTENCE LAYER 4PA165: Data Persistence I Where to store data Data can be stored on different places – Relational Database (RDBMS) – Object Database – XML Database – DMS (Document Management System) – CMS (Content Management System) – Post-relational database (Caché) • Temporary • Hiearchicke • Prostorove – No-SQL Database – Another Information System (CRM, ERP, etc.) PA165: Data Persistence I 5 Relational Databases • The most frequent data storage for enterprise applications – Relational data model is simple but very powerful – Suitable and sufficient for most of common applications – Good theoretical model (Relational Algebra, Relational Calculus) – Simplicity => High Performance (eg. due simple optimizations) – Proven and well established technology (40 years of development, tools, standards, reliability, high penetration, lots of experts, etc.) – Data are separated from application and can be easily shared between different applications – Independent on concrete platform or programming language PA165: Data Persistence I 6 Persistence Technologies • With Object Model (ORM or other model conversion) – Legacy EJB 2.x – Hibernate – JPA – JDO • With Relational Model – JDBC – Commons DB Utils – Spring JDBC – iBatis – Embedded SQL PA165: Data Persistence I 7 Architecture of persistence layer PA165: Data Persistence I 8 DB Persistence/DAO Tier Application Logic Presentation Tier JDBC / SQL Entity DTO Architecture of persistence layer • DAO (Data Access Object) design pattern – Separation persistence and data access from business logic – Allows to modify persistence implementation or replace persistence technology at all without affecting application logic. PA165: Data Persistence I 9 Transaction management • Transaction are not controlled on DAO level • Why? – Single transaction can contain more operations provided by different DAO components – Transaction management should be independent on persistent technology • Transaction management will be discussed later in lecture focused on Service Layer PA165: Data Persistence I 10 INTRODUCTION TO ORM PA165: Data Persistence I 12 What is ORM Object-relational mapping (ORM) – Technique for automatic conversion between object model and relational data model – You work with objects, but they are stored in a traditional relational database. INSERT INTO people (id, name) VALUES (1, "Pepa"); Person p = new Person(1, "Pepa"); em.persist(p); em.getTransaction().commit(); UPDATE people SET name = "Honza" WHERE id = 2; Person p = em.find(Person.class,2); p.setName("Honza"); em.getTransaction().commit(); PA165: Data Persistence I 13 Why ORM • As we already discussed, the most frequent storage is RDBMS • But we usually want to work with Object Model • Why Object Model? – It is natural for object oriented programming language – Working with Object Data Model is straightforward, friendly and easy – See example PA165: Data Persistence I 14 Why ORM: JDBC example public String getPersonName(long personId) throws SQLException { PreparedStatement st = null; try { st = connection.prepareStatement( "SELECT name FROM people WHERE id = ?"); st.setLong(1, personId); ResultSet rs = st.executeQuery(); if (rs.next()) { String result = rs.getString("name"); assert !rs.next(); return result; } else { return null; } } finally { if (st != null) { st.close(); } } } PA165: Data Persistence I 15 Why ORM: JPA Example public String getPersonName(long personId) { Person p = em.find(Person.class,personId); return p.getName(); } PA165: Data Persistence I 16 ORM: What We Get and Lost • ORM Benefits – Possibility to work with natural object model – Portability between different RDBMS with different SQL Dialect – Type checking at compile phase – No runtime error in SQL statements – Simplifies testing – Simpler and clearer code – More effective development (auto complete, access to JavaDoc, etc.) • ORM drawbacks – Less performance in some cases (ORM has some overhead). – No access to advantages of relational model and features of RDBMS (e.g. storage procedures) PA165: Data Persistence I 17 Basic terms Pojmy, které byste měli znát – JDBC, SQL, Transakce, Pojmy, které si definujeme – Entita – doménový objekt, který reprezentuje data ukládaná do databáze (např. osoba, faktura, předmět). – DTO (Data Transfer Object) – objekt, který slouží pro zapouzdření dat a jejich transport mezi komponentami. – POJO (Plain Old Java Object) – jednoduchá třída, na kterou nejsou kladeny žádné zvláštní požadavky. Nemusí implementovat žádné rozhraní, nemusí rozšiřovat žádnou jinou třídu, ani není závislá na žádné jiné třídě, balíku nebo frameworku. Jediné podmínky, které na ni mohou být kladeny, je přítomnost bezparametrického konstruktoru, a dodržení konvencí pro pojmenování get/set metod. PA165: Data Persistence I 18 Standards and Approaches Entity EJB (EJB 2.1/JSR 153; J2EE 1.4) – Vyžaduje aplikační server s EJB kontejnerem. – Entita je heavyweight komponenta, jejíž instance se nachází v EJB kontejneru a přístup k ní probíhá prostřednictvím vzdáleného volání metod. – Problém s latencemi (řeší se pomocí DTO, příp. DAO). – CMP a BMP – Od verze EJB 3.0 (JSR 220) je preferováno JPA. JDO (JDO 3.0/JSR 243) – Obecný standard pro perzistenci v Javě. – Není omezeno na relační databáze, objekty mohou být ukládány do úložiště libovolného typu JPA (JPA 2.0/JSR 317; Java EE 6) – Java EE standard pro ORM inspirovaný Hibernate. – Entita je lightweight POJO, který může být libovolně předáván mezi komponentami, lokálně i vzdáleně. PA165: Data Persistence I 19 EJB 2.x Entity public abstract class PersonBean implements EntityBean { private EntityContext context; public abstract Long getId(); public abstract void setId(Long id); public abstract String getName(); public abstract void setName(String name); public Long ejbCreate (Long id, String name) throws CreateException { setId(id); setName(name); return id; } public void ejbPostCreate (Long id, String name) throws CreateException {} public void setEntityContext(EntityContext ctx) { context = ctx; } public void unsetEntityContext() { context = null; } public void ejbRemove() {} public void ejbLoad() {} public void ejbStore() {} public void ejbPassivate() {} public void ejbActivate() {} public PersonDTO getPersonDTO() { return new PersonDTO(getId(),getName()); } } PA165: Data Persistence I 20 POJO Entity public class Person { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object o) { if (this == o) { return true; } if (getId() == null) { return false; } if (o instanceof Person) { return getId().equals(((Person) o).getId()); } else { return false; } } public int hashCode() { return id==null?0:id.hashCode(); } } PA165: Data Persistence I 21 Mapping Definition Prostřednictvím anotací – Definice objektového modelu i jeho mapování je na jednom místě. – Větší přehlednost, jednodušší vývoj, snazší údržba. Prostřednictvím externího souboru (obvykle XML) – nezávislost kódu entit na konkrétní technologii zajišťující ORM; – možnost měnit mapování bez nutnosti modifikovat kód. Pomocí speciálních JavaDoc komentářů – Z doby, kdy Java nepodporovala anotace. – Viz XDoclet. PA165: Data Persistence I 22 Generování schématu databáze na základě definice mapování – Máme vytvořené entity a definici mapování a chceme si ušetřit práci s vytvářením schématu databáze. – Je možné automaticky vytvářet tabulky při prvním spuštění aplikace. – Výhodné zejména při vývoji, kdy dochází ke změnám datového modelu. – Vhodné, pokud je datový model zcela pod kontrolou naší aplikace. – Problém, pokud se mění datový model a již máme v databázi existující data. Generování entit a definice mapování na základě schématu databáze – Máme vytvořené schéma databáze a chceme si ušetřit práci s vytvářením entit a definicí mapování (např. vyvíjíme aplikaci pro přístup k již existujícím datům). – Obvykle je nutné vygenerované soubory ručně opravit. PA165: Data Persistence I 23 JAVA PERSISTENCE API PA165: Data Persistence I 24 JPA Introduction Java Persistence API – POJO Entity, inspirované ORM nástrojem Hibernate – Jedná se o rozhraní, které implementují různé ORM nástroje od různých dodavatelů. – Obsahuje základní funkce, jednotlivé implementace mohou prostřednictvím svého proprietárního rozhraní poskytovat řadu dalších služeb a možností. Verze a specifikace – JPA 1.0 – součást Java EE 5; vzniklo jako součást EJB 3.0 (JSR 220), lze jej ale použít zcela nezávisle. – JPA 2.0 – součást Java EE 6; JSR 317. ORM nástroje implementující JPA – Hibernate – TopLink, TopLink Essentials – Eclipse Link (JPA 2.0) – Open JPA PA165: Data Persistence I 25 Entity in JPA Entity – Reprezentují jednotlivé doménové objekty. – Jsou klasické POJO, tj. jednduché a obyčejné objekty. – Entita má atributy, které reprezentují vlastnosti doménového objektu. – Atributy jsou přístupné pomocí get/set metod. – Entita musí mít bezparamentrický konstruktor a pokud má být používána k přenosu dat prostřednictvím RMI, musí být serializovatelná. Definice mapování – Způsob uložení entity do relační databáze je definován pomocí anotací, nebo pomocí XML souboru. – Důsledně se uplatňuje princip convention-over-configuration. PA165: Data Persistence I 26 JPA Entity @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object o) { if (this == o) { return true; } if (getId() == null) { return false; } if (o instanceof Person) { return getId().equals(((Person) o).getId()); } else { return false; } } public int hashCode() { return id==null?0:id.hashCode(); } } PA165: Data Persistence I 27 Example • Working With Entity PA165: Data Persistence I 28 Configuration Konfigurace – Uložena v souboru persistence.xml – Může obsahovat více tzv. Persistence Unit. Persistence Unit – Seznam tříd, které daná PU spravuje – Konfigurace připojení k databázi • JNDI název DataSource • JDBC url, jméno, heslo – Způsob řízení transakcí – Způsob generování tabulek při spuštění aplikace Konfigurační parametry – U JPA 1.0 nejsou názvy konfiguračních parametrů standardizovány, u JPA 2.0 již ano. – Parametry mohou být nastaveny také při vytváření instancí EntityManagerFactory a EntityManager PA165: Data Persistence I 29 Instance entity C JPA Architecture PA165: Data Persistence I 30 EntityManager EntityManagerFactory PersistenceContext PersistenceUnit Instance entity B Instance entity A Třída entity C Třída entity B Třída entity A Konfigurace, definice mapování Správa instancí entit Transakce 1 1 1 1..n 10..n 10..n Spravuje Konfiguruje 10..1 Načítá konfiguraci PU Vytváří EntityManager Umožňuje provádět operace s entitami Entity Lifecycle PA165: Data Persistence I 31 Managed New Does not exist Entity e = new Entity(); em.persist(e); Detached Deleted em.merge(e) em.remove(e) em.persist(e); Opuštění persistence contextu  Serializace a deserializace  Ukončení platnosti persistence contextu  Klonování nebo kopie em.refresh(e);Všechny změny entity jsou při commitu transakce automaticky uloženy do DB Quiz • Entity Lifecycle PA165: Data Persistence I 32 RELATIONSHIPS AND ADVANCED MAPPING PA165: Data Persistence I 34 Example • Relationships – OneToOne – OneToMany – ManyToOne – ManyToMany – Uniderctional – Bidirectional – Cascade Operations PA165: Data Persistence I 35 QUERYING PA165: Data Persistence I 36 Querying • JPQL – Query language similar to SQL – Supports scalar values, tuples, entities or constructed objects • Criteria API – From JPA 2.0 – Allows to build query programatically PA165: Data Persistence I 37 Example • JPQL – Executing simple query – Named queries – Returning scalar values – Returning tuples – Constructing objects • Criteria API – Simple example PA165: Data Persistence I 38 OTHER TECHNOLOGIES PA165: Data Persistence I 39 EJB 2.x • Incompatible with DAO Design Pattern – Actually, DAO Pattern was designed as replacement for EJB 2.x Entities • Requires Java EE Application server with EJB Container • Entity is heavyweight component, instances are located in EJB Container and accessed remotely • Problem with latencies (reason for introducing DAO and DTO design patterns) • CMP versus BMP • JPA is preferred from EJB 3.0 PA165: Data Persistence I 40 EJB 2.x Entity public abstract class PersonBean implements EntityBean { private EntityContext context; public abstract Long getId(); public abstract void setId(Long id); public abstract String getName(); public abstract void setName(String name); public Long ejbCreate (Long id, String name) throws CreateException { setId(id); setName(name); return id; } public void ejbPostCreate (Long id, String name) throws CreateException {} public void setEntityContext(EntityContext ctx) { context = ctx; } public void unsetEntityContext() { context = null; } public void ejbRemove() {} public void ejbLoad() {} public void ejbStore() {} public void ejbPassivate() {} public void ejbActivate() {} public PersonDTO getPersonDTO() { return new PersonDTO(getId(),getName()); } } PA165: Data Persistence I 41 Embedded SQL • SQL written directly in the code • Code is processed with special preprocessor before compiling • Preprocessor process SQL expressions, checks their validity, performs type checking a translates them into expression of used programming language. • Preprocessor requires database connection public String getPersonName(long personId) { String name; #sql { SELECT name INTO :name FROM people WHERE id = :personId }; return name; } PA165: Data Persistence I 42 Spring JDBC • Spring library implementing Template Method design pattern • Cleaner code, faster development, easier maintenance • Unlike ORM or Embedded SQL does not solve the problem with errors in SQL expressions, that become apparent until runtime JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); public String getPersonName(long personId) { return jdbcTemplate.queryForObject( "SELECT name FROM people WHERE id = ?", String.class,personId); } PA165: Data Persistence I 43 Apache Commons DBUtils • Another library implementing Template Method design pattern. QueryRunner queryRunner = new QueryRunner(dataSource); ResultSetHandler stringHandler = new ScalarHandler(); public String getPersonName(long personId) { return queryRunner.query( "SELECT name FROM people WHERE id = ?", stringHandler,personId); } PA165: Data Persistence I 44 iBatis/MyBatis • Originally Apache project, retired, currently developed as MyBatis • SQL Queries are separated from code – In XML file – In annotations (in new versions) • More powerful that simple libraries like Spring JDBC, more lightweight than ORM PA165: Data Persistence I 45 Questions ? 46PA165: Data Persistence I