What is persistence Object persistence means that individual
What is persistence? • Object persistence means that individual objects can outlive the process that created it • They can be saved to a data store and be -created at the later point in time re • Persistence is one of the fundamental concepts in application development • Persistence in Java normally means storing data in a relational database using SQL
Layered architecture • A typical, proven, high-level application architecture uses three layers: • A persistence layer is the basis in a layered architecture
Persistence solutions Java Database Connectivity Java application JDBC Hibernate Java Persistence API ORM implementation SQL-based relational database
Java Persistence API The Java Persistence API provides an object/relational mapping facility for managing relational data in Java applications "An ORM implementation is a complex beast – less complex than an application server, but more complex than a web application framework like Struts or Tapestry“ Hibernate in Action
Object-Relational Mapping Java Application Java Class Diagram Database ORM ER Diagram
Java Persistence • Java Persistence consists of three areas: • Java Persistence API • Query language • Object/relational mapping metadata • Specification • JPA 2. 1 (22 May 2013, part of Java EE 7) • JSR 328: http: //jcp. org/en/jsr/detail? id=338
Entities • • • An entity is a lightweight persistence domain object Java class that typically represents a table in a relational database, instances correspond to rows Requirements: • annotated with the javax. persistence. Entity annotation • public or protected, no-argument constructor • the class must not be declared final • no methods or persistent instance variables must be declared final
Requirements for Entities (cont. ) • Entities may extend both entity and non-entity classes • Non-entity classes may extend entity classes • Persistent instance variables must be declared private, protected, or package-private • No required business/callback interfaces • Example: @Entity public class Person { private String full. Name; public String get. Full. Name() { return full. Name; } public void set. Full. Name(String full. Name) { this. full. Name = full. Name; } }
Persistent Fields and Properties • The persistent state of an entity can be accessed: • • through the entity’s instance variables through Java. Beans-style properties • Supported types: • • primitive types, String, other serializable types, enumerated types other entities and/or collections of entities • All fields not annotated with @Transient or not marked as Java transient will be persisted to the data store!
Primary Keys in Entities Each entity must have a unique object identifier (persistent identifier) @Entity public class Employee { @Id private int id; primary key private String name; private Date age; public int get. Id() { return id; } public void set. Id(int id) { this. id = id; }. . . }
Persistent Identity • Identifier (id) in entity = primary key in database • Uniquely identifies entity in memory and in DB • Persistent identity types: • Simple id – single field/property @Id int id; • Compound id – multiple fields/properties @Id int id; @Id String name; • Embedded id – single field of PK class type @Embedded. Id Employee. PK id;
Identifier Generation • Identifiers can be generated in the database by specifying @Generated. Value on the identifier • Four pre-defined generation strategies: • AUTO, IDENTITY, SEQUENCE, TABLE • Specifying strategy of AUTO indicates that the provider will choose a strategy @Id @Generated. Value private int id;
Customizing the Entity Object • In most of the cases, the default values of annotation attributes are sufficient • By default the table name corresponds to the unqualified name of the class • Customization: @Entity(name = "FULLTIME_EMPLOYEE") public class Employee{ …… } • The defaults of columns can be customized using the @Column annotation @Id @Column(name = "EMPLOYEE_ID", nullable = false) private String id; @Column(name = "FULL_NAME" nullable = true, length = 100) private String name;
Managing Entities • Entities are managed by the entity manager • The entity manager is represented by javax. persistence. Entity. Manager instances • Each Entity. Manager instance is associated with a persistence context • A persistence context defines the scope under which particular entity instances are created, persisted, and removed
Persistence Context Application Entity. Manager My. Entity A My. Entity C My. Entity a My. Entity B My. Entity b Entities Entity state
Entity Manager • An Entity. Manager instance is used to manage the state and life cycle of entities within a persistence context • The Entity. Manager API: • • • creates and removes persistent entity instances finds entities by the entity’s primary key allows queries to be run on entities • There are two types of Entity Managers: • • Application-Managed Entity Managers Container-Managed Entity Managers
Application-Managed Entity. Manager Can be created manually in a program code: public class Persistence. Program { public static void main(String[] args) { Entity. Manager. Factory emf = Persistence. create. Entity. Manager. Factory("Some. PUnit"); Entity. Manager em = emf. create. Entity. Manager(); em. get. Transaction(). begin(); // Perform finds, execute queries, update entities, etc. em. get. Transaction(). commit(); em. close(); emf. close(); } }
Container-Managed Entity. Managers An Entity. Manager with a transactional persistence context can be injected by a container (e. g. Spring) @Transactional public class Persistence. Helper. Impl implements Persistence. Helper {. . . @Persistence. Context public void set. Entity. Manager(Entity. Manager em) { this. em = em; } public void save(Persistent. Entity object) { if (object. get. Id() == null) { get. Entity. Manager(). persist(object); } else { get. Entity. Manager(). merge(object); } } }
Operations on Entity Objects Entity. Manager API operations: • • • persist()- Insert the state of an entity into the db remove()- Delete the entity state from the db refresh()- Reload the entity state from the db merge()- Synchronize the state of detached entity with the pc find()- Execute a simple PK query create. Query()- Create query instance using dynamic JP QL create. Named. Query()- Create instance for a predefined query create. Native. Query()- Create instance for an SQL query contains()- Determine if entity is managed by pc flush()- Force synchronization of pc to database
Entity Instance’s Life Cycle • Instances are in one of four states: • • New Managed Detached Removed • The state of persistent entities is synchronized to the database when the transaction commits • To force synchronization of the managed entity to the data store, invoke the flush() method
Persistence Units • A persistence unit defines: • • a database connection settings a set of all entity classes that are managed by Entity. Manager instances in an application • Some set of entities can share one common provider (e. g. Top. Link), whereas other set of entities can depend on a different provider (e. g. Hibernate) • Persistence units are defined by the persistence. xml configuration file • should be located in project classpath folder META-INF
Hibernate. Persistence provider Sample configuration of persistence unit: <persistence xmlns="http: //java. sun. com/xml/ns/persistence" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" version="1. 0"> <persistence-unit name="hibernate_mysql" transaction-type="RESOURCE_LOCAL"> <provider>org. hibernate. ejb. Hibernate. Persistence</provider> <properties> <property name="hibernate. dialect" value="org. hibernate. dialect. My. SQLDialect"/> <property name="hibernate. hbm 2 ddl. auto" value="update"/> <property name="hibernate. connection. driver_class" value="com. mysql. jdbc. Driver"/> <property name="hibernate. connection. username" value="root"/> <property name="hibernate. connection. password" value="root"/> <property name="hibernate. connection. url" value="jdbc: mysql: //localhost/web"/> <property name="hibernate. show_sql" value="true"/> </properties> </persistence-unit> </persistence>
hibernate. hbm 2 ddl. auto • Automatically validates or exports schema DDL to the database when the Session. Factory is created. With create-drop, the database schema will be dropped when the Session. Factory is closed explicitly • Possible values: • • validate create update create-drop
Using JPA in Servlets
Java Persistence API in Servlets A simple scenario how to use Java Persistence API from Servlet web application 1. Add JPA libraries to the project 2. Create the Persistence Class (@Entity) 3. Create the Data Access Object (DAO) 4. Obtain Entity. Manager. Factory in the Servlet. Context. Listener and initialize DAO with it
JPA dependencies (Hibernate provider) Add to pom. xml (Maven configuration file): <dependency> <group. Id>org. hibernate</group. Id> <artifact. Id>hibernate-entitymanager</artifact. Id> <version>4. 2. 5. Final</version> </dependency> <group. Id>org. hibernate</group. Id> <artifact. Id>hibernate-core</artifact. Id> <version>4. 2. 5. Final</version> </dependency> <group. Id>org. hibernate. javax. persistence</group. Id> <artifact. Id>hibernate-jpa-2. 1 -api</artifact. Id> <version>1. 0. 0. Final</version> </dependency>
JPA dependencies (My. SQL driver) Add to pom. xml (Maven configuration file): <dependency> <group. Id>mysql</group. Id> <artifact. Id>mysql-connector-java</artifact. Id> <version>5. 1. 26</version> </dependency> You may also use some other vendor driver if you prefer different database
Creating an Entity @Entity public class Person { @Id @Generated. Value private Long id; private String full. Name; public Long get. Id() { return id; } public String get. Full. Name() { return full. Name; } public void set. Full. Name(String full. Name) { this. full. Name = full. Name; } }
Creating a DAO class public class Person. DAO { private Entity. Manager. Factory emf; public Person. DAO(Entity. Manager. Factory emf){ this. emf = emf; } public void save(Person person){ Entity. Manager em = emf. create. Entity. Manager(); em. get. Transaction(). begin(); em. persist(person); em. get. Transaction(). commit(); em. close(); } }
Obtaining Entity. Manager. Factory • In order to perform database operations, we need to obtain an Entity. Manager. Factory instance • We will use an application-managed approach • when using any kind of a container (e. g. Spring) more convenient container-managed approach may be used • A convenient approach is to create Entity. Manager. Factory once, encapsulating it in some sort of a singleton wrapper class (Persistence. Manager), and then use it for different purposes
Persistence. Manager public class Persistence. Manager { private Entity. Manager. Factory emf; private static final Persistence. Manager INSTANCE = new Persistence. Manager(); public static Persistence. Manager get. Instance() { return INSTANCE; } private Persistence. Manager() {} public Entity. Manager. Factory get. Entity. Manager. Factory() { if (emf == null) create. Entity. Manager. Factory(); return emf; } protected void create. Entity. Manager. Factory() { this. emf = Persistence. create. Entity. Manager. Factory("p_unit"); } public void close. Entity. Manager. Factory() { if (emf != null) { emf. close(); emf = null; }}}
Creating Entity. Manager. Factory @Web. Listener public class Persistence. Context. Listener implements Servlet. Context. Listener { public void context. Initialized(Servlet. Context. Event event) { Servlet. Context context = event. get. Servlet. Context(); Entity. Manager. Factory emf = Persistence. Manager. get. Instance(). get. Entity. Manager. Factory(); Person. DAO person. DAO = new Person. DAO(emf); context. set. Attribute("person. DAO", person. DAO); } public void context. Destroyed(Servlet. Context. Event event) { Persistence. Manager. get. Instance(). close. Entity. Manager. Factory(); } }
Using DAO in a Servlet @Web. Servlet("/person") public class Person. Servlet extends Http. Servlet { public void do. Post(Http. Servlet. Request request, Http. Servlet. Response response) throws Servlet. Exception, IOException { String full. Name = request. get. Parameter("full_name"); Person person = new Person(); person. set. Full. Name(full. Name); Person. DAO dao = (Person. DAO)request. get. Servlet. Context(). get. Attribute("person. DAO"); dao. save(p); } }
persistence. xml location • JPA configuration file persistence. xml should be placed inside WAR file in: <WAR>WEB-INFclassesMETA-INF • When using Maven directory structure, then valid place for persistence. xml is: <project_root>srcmainresourcesMETA-INF
JPQL Java Persistence Query Language
Introduction • The Java Persistence API specifies a query language that allows to define queries over entities and their persistent state • JPQL is an extension of EJB QL • More robust flexible and object-oriented than SQL • The persistence engine parse the query string, transform the JPQL to the native SQL before executing it
Creating Queries • Query instances are obtained using: • • Entity. Manager. create. Named. Query (static query) Entity. Manager. create. Query (dynamic query) • Query API: get. Result. List() – execute query returning multiple results get. Single. Result() – execute query returning single result execute. Update() – execute bulk update or delete set. First. Result() – set the first result to retrieve set. Max. Results() – set the maximum number of results to retrieve set. Parameter() – bind a value to a named or positional parameter set. Hint() – apply a vendor-specific hint to the query set. Flush. Mode()– apply a flush mode to the query when it gets run
Static (Named) Queries • Defined statically with the help of @Named. Query annotation together with the entity class • @Named. Query elements: • name - the name of the query that will be used with the create. Named. Query method • query – query string @Named. Query(name="find. All. Customers", query="SELECT c FROM Customer") Query find. All. Query = entity. Manager. create. Named. Query("find. All. Customers"); List customers = find. All. Query. get. Result. List();
Multiple Named Queries Multiple named queries can be logically defined with the help of @Named. Queries annotation @Named. Queries( { @Named. Query(name = “Mobile. select. All. Query” query = “SELECT M FROM MOBILEENTITY”), @Named. Query(name = “Mobile. delete. All. Query” query = “DELETE M FROM MOBILEENTITY”) } )
Dynamic Queries • Dynamic queries are queries that are defined directly within an application’s business logic • Worse efficiency and slower query execution, as the persistence engine has to do all the parsing and validation stuffs, along with mapping the JPQL to the SQL at the run-time public List find. All(String entity. Name){ return entity. Manager. create. Query( "select e from " + entity. Name + " e"). get. Result. List(); }
Named Parameters • • Named parameters are parameters in a query that are prefixed with a colon (: ) To bound parameter to an argument use method: • Query. set. Parameter(String name, Object value) public List find. With. Name(String name) { return em. create. Query( "SELECT c FROM Customer c WHERE c. name LIKE : cust. Name"). set. Parameter("cust. Name", name). get. Result. List(); }
Positional Parameters • Positional parameters are prefixed with a question mark (? ) followed the numeric position of the parameter in the query To set parameter values use method: • • Query. set. Parameter(integer position, Object value) public List find. With. Name(String name) { return em. create. Query( “SELECT c FROM Customer c WHERE c. name LIKE ? 1”). set. Parameter(1, name). get. Result. List(); }
Native Queries • Queries may be expressed in native SQL • Support for cases where it is necessary to use the native SQL of the target database in use Query q = em. create. Native. Query( "SELECT o. id, o. quantity, o. item " + "FROM Order o, Item i " + "WHERE (o. item = i. id) AND (i. name = 'widget')", com. acme. Order. class); • @Sql. Result. Set. Mapping annotaton is used for more advanced cases
Query Operations – Multiple Results • Query. get. Result. List() will execute a query and may return a List object containing multiple entity instances Query query = entity. Manager. create. Query(“SELECT C FROM CUSTOMER”); List<Mobile. Entity> mobiles = (List<Mobile. Entity>)query. get. Result. List(); • Will return a non-parameterized List object • Can only execute on select statements as opposed to UPDATE or DELETE statements • For a statement other than SELECT run-time Illegal. State. Exception will be thrown
Query Operations – Single Result • A query that returns a single entity object Query single. Select. Query = entity. Manager. create. Query( “SELECT C FROM CUSTOMER WHERE C. ID = ‘ABC-123’”); Customer cust. Obj = single. Select. Query. get. Single. Result(); • If the match wasn’t successful, then Entity. Not. Found. Exception is returned • If more than one matches occur during query execution a run-time exception Non. Unique. Result. Exception will be thrown
Paging Query Results int max. Records = 10; int start. Position = 0; String query. String = “SELECT M FROM MOBILEENTITY”; while(true){ Query select. Query = entity. Manager. create. Query(query. String); select. Query. set. Max. Results(max. Records); select. Query. set. First. Result(start. Position); List<Mobile. Entity> mobiles = entity. Manager. get. Result. List(query. String); if (mobiles. is. Empty()){ break; } process(mobiles); // process the mobile entities entity. Manager. clear(); // detach the mobile objects start. Position = start. Position + mobiles. size(); }
Flushing Query Objects • Two modes of flushing query objects • AUTO (default) and COMMIT • AUTO - any changes made to entity objects will be reflected the very next time when a SELECT query is made • COMMIT - the persistence engine may only update all the state of the entities during the database COMMIT
JPQL Statement Language • JPQL statement types: • SELECT, UPDATE, DELETE • Supported clauses: • • • FROM WHERE GROUP_BY HAVING ORDER BY … • Conditional expressions, aggregate functions, …
OO-style vs. SQL-style queries • • The main difference is that you query the application model, i. e. the entities, rather than any database tables Productivity can be increased if OO-style queries, e. g. employee. XYZ. get. Manager(). get. Address() are automatically translated by the ORM engine into correct SQL code, e. g. SELECT t 3. * FROM EMP t 1, EMP t 2, ADDR t 3 WHERE t 1. EMP_ID = “XYZ” AND t 1. MGR_ID = t 2. EMP_ID AND t 2. ADDR_ID = t 3. ADDR_ID • Notice that the two-step object traversal was packed into a single DB query
More about JPA Relations Inheritance
Entity Relationships • There are four types of relationship multiplicities: • • @One. To. One @One. To. Many @Many. To. One @Many. To. Many • The direction of a relationship can be: • • bidirectional – owning side and inverse side unidirectional – owning side only • Owning side specifies the physical mapping • Inverse side is indicated by “mapped. By” attribute
One. To. One Mapping [1] Create unidirectional relationship from Singer to Person: @Entity @Discriminator. Value("SINGER") public class Singer extends Artist{ @One. To. One private Person person; . . . } Result: In database “person_id” field is added to “artist” table, which contains foreign keys to “person” table
One. To. One Mapping [2] Make this relationship bidirectional: @Entity public class Person implements Persistent. Entity {. . . @One. To. One(mapped. By="person") private Singer singer. Info; . . . }
Many. To. One Mapping @Entity public class Sale { @Id int id; . . . @Many. To. One Customer cust; } } SALE ID . . . CUST_ID CUSTOMER ID . . .
One. To. Many Mapping @Entity public class Customer { @Id int id; . . . @One. To. Many(mapped. By=“cust”) Set<Sale> sales; } @Entity public class Sale { @Id int id; . . . @Many. To. One Customer cust; } CUSTOMER ID . . . SALE ID . . . CUST_ID
Additional notes “Many” end of the bidirectional Many. To. One relationship cannot be the inverse side of the relationship • @Many. To. One annotation cannot contain attribute “mapped. By”
General rules • If “One” end of the relationship is the owning side, then foreign key column is generated for this entity in database • If “Many” end of the relationship is the owning side (e. g. unidirectional Many. To. One or any kind of Many. To. Many), then join table is generated
Many. To. Many Mapping @Entity public class Customer {. . . @Many. To. Many @Join. Table( name="CUSTOMER_SALE", join. Columns=@Join. Column( name="CUSTOMER_ID", referenced. Column. Name="customer_id"), inverse. Join. Columns=@Join. Column( name="SALE_ID", references. Column. Name="sale_id") Collection<Sale> sales; } @Entity public class Sale {. . . @Many. To. Many(mapped. By=“sales”) Collection<Customer> customers; }
Relation Attributes • Cascade. Type • ALL, PERSIST, MERGE, REMOVE, REFRESH • Fetch. Type • LAZY, EAGER @Many. To. Many( cascade = {Cascade. Type. PERSIST, Cascade. Type. MERGE}, fetch = Fetch. Type. EAGER)
Entity Inheritance • An important capability of the JPA is its support for inheritance and polymorphism • Entities can inherit from other entities and from non-entities • The @Inheritance annotation identifies a mapping strategy: • • • SINGLE_TABLE JOINED TABLE_PER_CLASS
Inheritance Example 1 @Entity @Inheritance(strategy=Inheritance. Type. SINGLE_TABLE) @Discriminator. Column(name="DISC", discriminator. Type=Discriminator. Type. STRING) @Discriminator. Value("CUSTOMER") public class Customer {. . . } @Entity @Discriminator. Value("VCUSTOMER") public class Valued. Customer extends Customer {. . . } • • SINGLE_TABLE strategy - all classes in the hierarchy are mapped to a single table in the database Discriminator column - contains a value that identifies the subclass Discriminator type - {STRING, CHAR, INTEGER} Discriminator value - value entered into the discriminator column for each entity in a class hierarchy
Inheritance Examples 2 & 3 @Entity @Inheritance(strategy=Inheritance. Type. JOINED) public class Customer {. . . } @Entity public class Valued. Customer extends Customer {. . . } @Entity @Inheritance(strategy=Inheritance. Type. TABLE_PER_CLASS) public class Customer { @Id @Generated. Value(strategy = Generation. Type. TABLE) private Long id; . . . } @Entity public class Valued. Customer extends Customer {. . . }
Inheritance Example 3 @Entity @Inheritance(strategy=Inheritance. Type. SINGLE_TABLE) @Discriminator. Column(name="DISC", discriminator. Type=Discriminator. Type. STRING) @Discriminator. Value("CUSTOMER") public class Customer {. . . } @Entity @Discriminator. Value("VCUSTOMER") public class Valued. Customer extends Customer {. . . } • • SINGLE_TABLE strategy - all classes in the hierarchy are mapped to a single table in the database Discriminator column - contains a value that identifies the subclass Discriminator type - {STRING, CHAR, INTEGER} Discriminator value - value entered into the discriminator column for each entity in a class hierarchy
Resources • Java EE 7 Tutorial: Introduction to the Java Persistence API http: //docs. oracle. com/javaee/7/tutorial/doc/persistenc e-intro. htm#BNBPZ • JPQL Language Reference http: //openjpa. apache. org/builds/1. 0. 2/apache-openjpa 1. 0. 2/docs/manual/jpa_langref. html
- Slides: 65