Java Persistence API 2.x

1,376 views
1,220 views

Published on

An introduction to the Java Persistence API 2.x (JPA). Namely, this set of slides first introduces the problem of impedance mismatch between the object model and the relation model. Then, the EntityManager's public interface is discussed, together with the parallelism between a persistence context and a L1 cache. The issue of encapsulating the different application's use cases (which are exposed by the service objects) is solved by means of the @Transactional annotation, which provides a declarative way of demarcating the application's transactional boundaries. It follows an in-depth explanation on how to integrate a local, container-managed EntityManager within an existing Spring MVC application, so as to correctly support the propagation of the persistence context throughout the different beans involved in the same transaction. We then turn our attention to the problem of mapping relationships, thus introducing the @OneToMany, @ManyToMany and @OneToOne annotations. The additional topics of how to cascade operations and how to support lazy loading are covered as well. The presentation concludes with a discussion on how to use both the Criteria and Query API (and JPQL) to query the underlying database.

Published in: Education, Technology
3 Comments
8 Likes
Statistics
Notes
No Downloads
Views
Total views
1,376
On SlideShare
0
From Embeds
0
Number of Embeds
11
Actions
Shares
0
Downloads
0
Comments
3
Likes
8
Embeds 0
No embeds

No notes for slide

Java Persistence API 2.x

  1. 1. Java Persistence API Ilio Catallo - info@iliocatallo.it
  2. 2. Outline • Object vs. rela/onal model • En//es and EntityManager • Integra/ng JPA into Spring • Mapping rela/onships • Querying the data source • References
  3. 3. Object vs. rela.onal model
  4. 4. Object vs. rela.onal model The end-point of every Web applica5on is the DBMS
  5. 5. Object vs. rela.onal model In many cases, the DBMS has been around for much longer than the Web applica;on
  6. 6. Object vs. rela.onal model It is up to the object model of the Web app to find ways to work with the database schema
  7. 7. Object vs. rela.onal model The technique of bridging the gap between the object model and the rela7onal model is known as object-rela+onal mapping (ORM)
  8. 8. Object vs. rela.onal model Object-rela+onal mapping techniques try to map the concepts from one model onto another
  9. 9. Impedance mismatch ┌───────────────────────────────┬──────────────────────────────┐ │////////// OOP Model //////////│////// Relational model /////│ ├───────────────────────────────┼──────────────────────────────┤ │ Classes, objects │ Tables, rows │ ├───────────────────────────────┼──────────────────────────────┤ │ Attributes, properties │ Columns │ ├───────────────────────────────┼──────────────────────────────┤ │ Identity │ Primary key │ ├───────────────────────────────┼──────────────────────────────┤ │ References to other entities │ Foreign key │ ├───────────────────────────────┼──────────────────────────────┤ │ Inheritance, polymorphism │ Not supported │ ├───────────────────────────────┼──────────────────────────────┤ │ Methods │ Stored procedures, triggers │ ├───────────────────────────────┼──────────────────────────────┤ │ Code is portable │ Code is vendor-depending │ └───────────────────────────────┴──────────────────────────────┘
  10. 10. The challenge of mapping one model to the other lies in the concepts in each for which there is no logical equivalent in the other
  11. 11. Impedance mismatch As a result, moving data back and forth between a DBMS and the object model is a lot harder than it needs to be
  12. 12. Impedance mismatch Java developers find themselves spending effort in wri5ng lots of code to convert rows and columns into objects
  13. 13. Impedance mismatch
  14. 14. The problem with JDBC JDBC has been the first major support for database persistence
  15. 15. The problem with JDBC JDBC offers an abstrac'on of the proprietary client programming interfaces provided by database vendors
  16. 16. The problem with JDBC Although JDBC is portable, the SQL language is not
  17. 17. The problem with JDBC It is rare to write SQL of any complexity that runs unchanged on two major database pla:orms
  18. 18. Java Persistence API The Java Persistence API (JPA) bridges the gap between object- oriented domain models and rela:onal database systems
  19. 19. Java Persistence API JPA 2.1 was developed by the JSR-338 so:ware expert group
  20. 20. Java Persistence API Despite its ini)al associa)on with EJBs, JPA is a JSE API, as reflected by its belonging to the java.persistence package
  21. 21. Java Persistence API JPA provides an ease-of-use abstrac5on on top of JDBC ┌──────────────────┐ ┌──────────────────┐ │ Java │ │ Vendor- │ │ Persistence API │ │ specific API │ └──────────────────┘ └──────────────────┘ ┌───────────────────────────────────────┐ │ │ The persistence provider │ Persistence provider │ is in charge of the ORM │ │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ │ JDBC provides methods │ JDBC │ for querying and updating │ │ data in the database └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ │ │ DBMS │ │ │ └───────────────────────────────────────┘
  22. 22. Java Persistence API The code can therefore be isolated from vendor-specific peculiari1es and rela1on model peculiari1es ┌──────────────────┐ ┌──────────────────┐ │ Java │ │ Vendor- │ │ Persistence API │ │ specific API │ └──────────────────┘ └──────────────────┘ ┌───────────────────────────────────────┐ │ │ The persistence provider │ Persistence provider │ is in charge of the ORM │ │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ │ JDBC provides methods │ JDBC │ for querying and updating │ │ data in the database └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ │ │ DBMS │ │ │ └───────────────────────────────────────┘
  23. 23. JPA main features • POJO persistence • Non-intrusiveness • Object queries
  24. 24. POJO persistence JPA provides a Plain Old Java Object (POJO) persistence model public class Employee { private int id; private String name; private long salary; public Employee() {...} // other methods (e.g., getters and setters) }
  25. 25. POJO persistence There is nothing special about the objects being persisted public class Employee { private int id; private String name; private long salary; public Employee() {...} // other methods (e.g., getters and setters) }
  26. 26. POJO persistence Any exis)ng non-final class with a default constructor can be made persistable public class Employee { private int id; private String name; private long salary; public Employee() {...} // other methods (e.g., getters and setters) }
  27. 27. Non-intrusiveness The persistence API exists as a separate layer from the domain model ┌──────┐┌────────────────────────────────┐ │ D ││ │ │ o ││ Presentation layer │ │ m ││ │ │ a │└────────────────────────────────┘ │ i │┌────────────────────────────────┐ │ n ││ │ │ ││ Service layer │ │ m ││ │ │ o │└────────────────────────────────┘ │ d │┌────────────────────────────────┐ │ e ││ │ │ l ││ Persistence layer │ │ ││ │ └──────┘└────────────────────────────────┘
  28. 28. Non-intrusiveness That is, the persisted objects are not aware of the persistence layer ┌──────┐┌────────────────────────────────┐ │ D ││ │ │ o ││ Presentation layer │ │ m ││ │ │ a │└────────────────────────────────┘ │ i │┌────────────────────────────────┐ │ n ││ │ │ ││ Service layer │ │ m ││ │ │ o │└────────────────────────────────┘ │ d │┌────────────────────────────────┐ │ e ││ │ │ l ││ Persistence layer │ │ ││ │ └──────┘└────────────────────────────────┘
  29. 29. Object queries JPA comes with an object-oriented query language that operates on classes and objects, rather than tables and rows SELECT c FROM Category c WHERE c.items is NOT EMPTY
  30. 30. En##es and EntityManager
  31. 31. En##es in the rela#onal paradigm In the rela*onal paradigm, an en#ty is something that can be recognized to have a7ributes and rela*onships id departOn ● ○ │ │ ┌───┴───────────┴─────┐ │ │ arriveOn │ Flight │─────○ │ │ └─────────────────────┘
  32. 32. En##es in the rela#onal paradigm An en%ty has an independent existence and can be uniquely iden/fied id departOn ● ○ │ │ ┌───┴───────────┴─────┐ │ │ arriveOn │ Flight │─────○ │ │ └─────────────────────┘
  33. 33. En##es in the rela#onal paradigm An en%ty may par$cipate in rela$onships with any number of other en%%es in a number of standard ways +---------+ +---------+ +----------+ | | | | | | | +-----> +------> | | | | | | | +---------+ +---------+ +----------+ Flight FlightLeg Airport
  34. 34. En##es in the OO paradigm In the object-oriented paradigm, we would add behavior to an en7ty and call it a class public class Flight { private List<FlightLeg> legs; private BigDecimal totalCost; public Flight(...) {...} public boolean isNonStop() {...} public long getTotalTravelTime() {...} // other methods }
  35. 35. The intui)on behind ORM Hence, the intui%on behind object-rela2onal mapping is that • Classes correspond to tables • Objects correspond to tuples
  36. 36. En#ty classes The @Entity annota)on is used to qualify a class as an en'ty @Entity public class Employee { @Id private int id; private String name; private long salary; public Employee() { ... } // other methods (e.g., getters and setters) }
  37. 37. En#ty classes En#ty objects are just plain-old Java objects Employee emp1 = new Employee(12, "Jon Snow"); Employee emp2 = new Employee(20, "Portgas D. Ace");
  38. 38. En#ty requirements En##es must respect some requirements • The en'ty class must have a public or protected default constructor • The en'ty class must not be final
  39. 39. En#ty requirements En##es must respect some requirements • No method or variables of the en3ty class may be final • If an en3ty object is to be passed as a detached object, the Serializable interface must be implemented
  40. 40. Persistence unit We refer to the set of en(ty classes as the persistence unit @Entity public class Employee { ... } @Entity public class Department { ... } @Entity public class ParkingSpace { ... }
  41. 41. EntityManager EntityManager is the central authority for all persistence ac/ons
  42. 42. EntityManager EntityManager provides methods for crea0ng queries, finding objects, synchronizing, and inser0ng objects into the DB
  43. 43. EntityManager The EntityManager API directly maps to CRUD opera8ons • persist (INSERT) • merge (UPDATE) • remove (DELETE) • find (SELECT)
  44. 44. Crea%ng a new en%ty En#ty objects do not become persistent just by invoking the new operator1 Employee e = new Employee(12, "Jon Snow”) 1 How would they auto-magically become persistent? A:er all, we said that en<<es objects are just POJOs
  45. 45. Crea%ng a new en%ty Newly-created objects are in the transient state, since the EntityManager does not know they exist yet Employee e = new Employee(12, "Jon Snow")
  46. 46. Persis&ng an en&ty En#ty objects remain transient un#l we no#fy the EntityManager of their existence Employee e = new Employee(12, "Jon Snow")
  47. 47. Persis&ng an en&ty The persist() method no#fies the En+tyManager of the existence of a given transient en+ty object2 Employee emp = new Employee(12, "Jon Snow"); entityManager.persist(emp); 2 Remembr that the persist() method does not actually cause the en3ty object to be immediately persisted, we are just sending a no3fica3on to the EntityManager
  48. 48. Persis&ng an en&ty The en&ty object enters the managed state Employee emp = new Employee(12, "Jon Snow"); entityManager.persist(emp);
  49. 49. Persis&ng an en&ty EntityManager makes sure that each managed object is synchronized with the related database tuple Employee emp = new Employee(12, "Jon Snow"); entityManager.persist(emp);
  50. 50. Persistence context The set of managed objects is called the persistence context ┌─────────────────────────────┐ │ │ │ ● o1 │ ● o5 │ │ │ ● o4 │ ● o6 │ │ │ ● o2 │ │ ● o3 │ ● o7 │ │ └─────────────────────────────┘ Persistence context
  51. 51. Persistence context EntityManger is the persistence context supervisor, whose responsibility is to keep in sync managed objects with tuples EntityManager ◊ │ ┌──────────────────┼──────────┐ │ │ │ │ │ │ │ ● o1 │ ● o5 │ │ │ ● o4 │ ● o6 │ │ │ ● o2 │ │ ● o3 │ ● o7 │ │ └─────────────────────────────┘ Persistence context
  52. 52. Persistence context Each EntityManager has its own persistence context, and there may exist several EntityManagers at once EntityManager A EntityManager B ◊ ◊ │ │ ┌──────────────────┼──────────┐ ┌──────────────────┼──────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ ● o1 │ │ ● o5 │ ● o9 │ │ │ │ │ ● o4 │ │ ● o7 │ ● o8 │ │ │ │ │ ● o2 │ │ ● o6 │ │ ● o3 │ │ │ ● o10 │ │ │ │ └─────────────────────────────┘ └─────────────────────────────┘ Persistence context A Persistence context B
  53. 53. Finding an en)ty The find() method finds en*ty objects by primary key Employee emp = entityManager.find(Employee.class, 12);
  54. 54. Finding an en)ty When the call completes, the returned en2ty object is in the managed state Employee emp = entityManager.find(Employee.class, 12);
  55. 55. Finding an en)ty The find() method returns null if the en/ty cannot be found Employee emp = entityManager.find(Employee.class, 12);
  56. 56. Removing an en+ty The remove() method removes the data associated with an en/ty object from the database entityManager.remove(emp);
  57. 57. Removing an en+ty The remove() method will also detach the en/ty object entityManager.remove(emp);
  58. 58. Removing an en+ty Once detached, an en+ty is no longer managed by the related EntityManager, i.e., it is no longer part of its persistence context entityManager.remove(emp);
  59. 59. Removing an en+ty Since the related tuple is deleted, the en1ty objects enters the removed state entityManager.remove(emp);
  60. 60. Removing an en+ty Removed en))es cannot be made managed again entityManager.remove(emp);
  61. 61. En#ty’s lifecycle +-------------+ | | | Persisted | | | +------+------+ | | find()/ | query | +-------------+ +------v-------+ +-----------+ new | | persist() | | remove() | | +----------> Transient +-------------> Managed +------------> Removed | | | | | | | +-------------+ +---+------^---+ +-----------+ | | out of scope/ | | merge()/ serialized/ | | refresh() cloned | | | | +---v------+---+ | | | Detached | | | +--------------+
  62. 62. Iden%fier genera%on Some%mes, applica%ons do not want to explicitly manage uniqueness in some aspect of their domain model
  63. 63. Iden%fier genera%on The persistence provider can automa&cally generate an iden0fier for every en0ty object of a given type
  64. 64. Iden%fier genera%on This persistence provider’s feature is called iden%fier genera%on and is specified by the @GeneratedValue annota7on @Entity public class Employee {     @Id @GeneratedValue     private int id;     ... }
  65. 65. Iden%fier genera%on Applica'ons can choose one out of four genera*on strategies ┌──────────────────────────────┬─────────────────────────────────────────┐ │/// Id generation strategy ///│////////////// Description /////////////│ ├──────────────────────────────┼─────────────────────────────────────────┤ │ │The provider generates identifiers by │ │ AUTO │using whatever strategy it wants │ │ │ │ ├──────────────────────────────┼─────────────────────────────────────────┤ │ │Identifiers are generated according to a │ │ TABLE │generator table │ │ │ │ ├──────────────────────────────┼─────────────────────────────────────────┤ │ │If the underlying DB supports sequences, │ │ SEQUENCE │the provider will use this feature for │ │ │generating ids │ ├──────────────────────────────┼─────────────────────────────────────────┤ │ │If the underlying DB supports primary key│ │ IDENTITY │identity columns, the provider will use │ │ │this feature for generating ids │ └──────────────────────────────┴─────────────────────────────────────────┘
  66. 66. AUTO strategy Remember that the AUTO mode is a genera0on strategy mainly meant for developing prototypes @Entity public class Employee {     @Id @GeneratedValue(strategy=GenerationType.AUTO)     private int id;     ... }
  67. 67. AUTO strategy In any other situa.on, it would be be4er to use other genera.on strategies @Entity public class Employee {     @Id @GeneratedValue(strategy=GenerationType.AUTO)     private int id;     ... }
  68. 68. Integra(ng JPA into Spring
  69. 69. Required steps To use JPA in our Spring Web applica5on we need to 1. Define a data source 2. Understand how to produce EntityManager instances 3. Introduce transac8onal seman8cs into the service layer 4. Write JPA-based repository beans
  70. 70. 1. Defining a data source
  71. 71. Data source Regardless of the persistence framework, we need to configure a reference to a data source
  72. 72. Pooled data source When developing mul/threading applica/ons, the common recommenda/on is to use a pooled data source
  73. 73. Pooled data source A pooled data source is a data source that draws its connec2ons from a connec%on pool
  74. 74. Pooled data source Unfortunately, Spring does not provide a na5ve pooled data source
  75. 75. Pooled data source We will use the pooled data source coming from the Apache Database Connec/on Pooling (DBCP) project
  76. 76. Declaring the data source By altering dataSource-context.xml, we can declare the new data source as a bean in the back-end container <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://server:3306/db_schema"/> <property name="username" value=”dbuser"/> <property name="password" value=”dbpassword"/> </bean>
  77. 77. Declaring the data source BasicDataSource is the class implemen-ng the pooled data source <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://server:3306/db_schema"/> <property name="username" value=”dbuser"/> <property name="password" value=”dbpassword"/> </bean>
  78. 78. Declaring the data source com.mysql.jdbc.Driver is the class implemen-ng the JDBC driver <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://server:3306/db_schema"/> <property name="username" value=”dbuser"/> <property name="password" value=”dbpassword"/> </bean>
  79. 79. Maven dependencies As usual, we can use Maven to automa1cally resolve dependencies <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.1.1</version> </dependency>
  80. 80. Maven dependencies As usual, we can use Maven to automa1cally resolve dependencies <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
  81. 81. 2. Obtaining an EntityManager
  82. 82. Obtaining an EntityManager Although we discussed the role of EntityManager, we s2ll do not know how to obtain an EntityManager instance
  83. 83. Obtaining an EntityManager The JPA specifica.on defines two kinds of EntityManagers • Applica(on-managed • Container-managed
  84. 84. Applica'on-managed Applica'on-managed EntityManagers are created by the applica.on itself EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPersistenceUnit"); EntityManager em = emf.createEntityManager();
  85. 85. Applica'on-managed The applica*on is responsible for every aspect of the EntityManager’s lifecycle EntityManager em = emf.createEntityManager(); ... entityManager.close();
  86. 86. Applica'on-managed The applica*on also needs to manually manage transac'ons entityManager.getTransaction().begin(); entityManager.getTransaction().commit();
  87. 87. Applica'on-managed This kind of EntityManager is typical of JSE applica*ons
  88. 88. Container-managed Container-managed EntityManagers are created by a container, which also injects them into the applica5on components
  89. 89. EntityManager beans Spring supports both types of EntityManager instances
  90. 90. EntityManager beans • LocalEntityManagerFactoryBean for applica+on-managed EntityManagers • LocalContainerEntityManagerFactoryBean for container-managed EntityManagers3 3 Actually, LocalEntityManagerFactoryBean (resp. LocalContainerEntityManagerFactoryBean) produces applica5on-managed (resp. container-managed) EntityManagerFactorys, which will in turn produce applica5on-managed (resp. container-managed) EntityManagers
  91. 91. EntityManager beans The following declares a factory bean for container-managed EntityManagers in dataSource-context.xml <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="it.polimi.awt.springmvc.domain"/> <property name="persistenceUnitName" value=”MyPersistenceUnit"/> ... </bean>
  92. 92. EntityManager beans dataSource is the data source bean we previously declared <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="it.polimi.awt.springmvc.domain"/> <property name="persistenceUnitName" value=”MyPersistenceUnit"/> ... </bean>
  93. 93. EntityManager beans it.polimi.awt.springmvc.domain is the package containing the classes to be persisted <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="it.polimi.awt.springmvc.domain"/> <property name="persistenceUnitName" value=”MyPersistenceUnit"/> ... </bean>
  94. 94. EntityManager beans MyPersistenceUnit is the name of the persistence unit <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="it.polimi.awt.springmvc.domain"/> <property name="persistenceUnitName" value=”MyPersistenceUnit"/> </bean>
  95. 95. Persistence provider Several possible JPA implementa3ons can be used as the persistence provider • EclipseLink • Hibernate • OpenJPA • TopLink
  96. 96. Persistence provider One way to tell Spring which implementa3on to use is to declare a JpaVendorAdapter bean in dataSource-context.xml <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"/> </bean>
  97. 97. Persistence provider Specifically, we use HibernateJpaVendorAdapter to denote that Hibernate is our persistence provider <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"/> </bean>
  98. 98. Persistence provider We set the database property to MYSQL to denote that MySQL is the underlying RDBMS <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"/> </bean>
  99. 99. Persistence provider We can now set-inject our JpaVendorAdapter bean into the LocalContainerEntityManagerFactoryBean: <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="it.polimi.awt.springmvc.domain"/> <property name="persistenceUnitName" value=”MyPersistenceUnit"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> </bean>
  100. 100. Maven dependencies <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.1.0.Final</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.0.Final</version> </dependency>
  101. 101. Alterna(ves exist No#ce we managed to integrate JPA in Spring by solely adding beans into the back-end container
  102. 102. persistence.xml That is, we did not have to introduce the standard JPA deployment descriptor file persistence.xml
  103. 103. persistence.xml <persistence> <persistence-unit name="MyPersistenceUnit"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://serverurl:3306/db-schema"/> <property name="javax.persistence.jdbc.user" value="dbuser"/> <property name="javax.persistence.jdbc.password" value="dbpasswd"/> </properties> </persistence-unit> </persistence>
  104. 104. 3. Dealing with transac1ons
  105. 105. Transac'ons In so&ware, all-or-nothing opera3ons are called transac'ons Everything goes well +-------------------> +-----------------------+ | | | | | 1. Verify seats | | Purchase ticket | 2. Reserve seat | | +-----------------------> 3. Receive payment +----+ | 4. Issue ticket | | | | | +-----------------------+ | +--------------------> Something goes wrong
  106. 106. Transac'ons Transac'ons allow grouping several opera'ons into a single unit of work that either fully happens or fully does not happen Everything goes well +-------------------> +-----------------------+ | | | | | 1. Verify seats | | Purchase ticket | 2. Reserve seat | | +-----------------------> 3. Receive payment +----+ | 4. Issue ticket | | | | | +-----------------------+ | +--------------------> Something goes wrong
  107. 107. Transac'onal boundary The service layer is the transac'onal boundary of the applica1on ┌──────┐┌────────────────────────────────┐ │ D ││ │ │ o ││ Presentation layer │ │ m ││ │ │ a │└────────────────────────────────┘ │ i │╔════════════════════════════════╗ │ n │║ ║ │ │║ Service layer ║ │ m │║ ║ │ o │╚════════════════════════════════╝ │ d │┌────────────────────────────────┐ │ e ││ │ │ l ││ Persistence layer │ │ ││ │ └──────┘└────────────────────────────────┘
  108. 108. Transac'onal boundary If a service method makes mul3ple calls against one or more persistence beans, we want those calls to operate as part of a single transac,on
  109. 109. Transac'onal boundary To handle this, the service layer needs a way to embed its persistence calls within the context of a transac,on
  110. 110. Transac'onal boundary Transaction | +-----------------------------------------------|-------------------------------------------------+ | | | | | | | +-----------------v-----------------+ | | | | | | | AccountService.transferFunds() | | | | | | | +-----------------+-----------------+ | | | | | | | | | | | | | | +---------------------------------------------------------------+ | | | | | | | | | | | | +------------v-----------+ +-----------v------------+ +-----------v-----------+ | | | | | | | | | | | AccountRepository | | AccountRepository | | LogRepository | | | | .update(account1) | | .update(account2) | | .create(entry) | | | | | | | | | | | +------------------------+ +------------------------+ +-----------------------+ | | | | | +-------------------------------------------------------------------------------------------------+
  111. 111. Transac'on managers Spring does not directly manage transac1ons
  112. 112. Transac'on managers Instead, it provides a selec1on of transac'on managers • JpaTransactionManager • JtaTransactionManager • JdoTransactionManager
  113. 113. Transac'on managers Each such transac+on manager acts as a façade to a pla2orm- specific implementa+on • JpaTransactionManager • JtaTransactionManager • JdoTransactionManager
  114. 114. Declaring a transac-on manager The transac+on manager of interest needs to be declared in dataSource-context.xml <bean id=”transactionManager” class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="emf"/> </bean>
  115. 115. Declaring a transac-on manager JpaTransactionManager needs to be wired to a EntityManagerFactory <bean id=”transactionManager” class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="emf"/> </bean>
  116. 116. Declaring a transac-on manager JpaTransactionManager collaborates with the EntityManager that is produced by the factory to conduct transac4ons <bean id=”transactionManager” class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="emf"/> </bean>
  117. 117. Two types of transac/ons Spring provides two ways of specifying transac3ons • Programma(c transac(ons • Declara(ve transac(ons
  118. 118. Declara've transac'ons Most Spring users choose declara've transac'on management, as this op2on has the least impact on applica2on code
  119. 119. Declara've transac'ons Declara've transac'ons allow keeping business code free from repe$$ve transac$on demarca$on code public void saveAccount(Account account) { txTemplate.execute(new TransactionCallback<Void>() { public void doInTransaction(TransactionStatus txStatus) { try { repository.saveAccount(account); } catch (RuntimeException e) { txStatus.setRollbackOnly(); throw e; } } }); }
  120. 120. @Transactional The @Transactional annota)on specifies that an interface, class, or method must have transac'onal seman'cs @Service @Transactional public class AccountServiceImpl implements AccountService { ... }
  121. 121. @Transactional From this point on, opera/ons will be transac'onal @Service @Transactional public class AccountServiceImpl implements AccountService { ... }
  122. 122. @Transactional When needed, addi$onal transac-onal seman$cs can be specified (e.g., marking the transac-ons as read-only) @Service @Transactional(readOnly = true) public class AccountServiceImpl implements AccountService { ... }
  123. 123. Ac#vate declara#ve transac#ons A simple addi+on to dataSource-context.xml allows ac+va+ng declara+ve transac+ons <tx:annotation-driven/>
  124. 124. Maven dependencies As usual, we can use Maven to automa1cally resolve dependencies <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.2.5.RELEASE</version> </dependency>
  125. 125. 4. How to write JPA repository beans
  126. 126. Persistence context Let us intend the persistence context as a cache
  127. 127. Persistence context The objects we alter could then be intended as a in-memory copy of the data in the database
  128. 128. Persistence context Hence, by doing account.getBalance() we access the in- memory object rather than taking the data from the database
  129. 129. Persistence context Similarly, by doing account.setBalance(5000) we alter the in-memory object, rather than the data on the database
  130. 130. Persistence context At a certain point the persistence context needs to be flushed so as to mirror the changes in the database
  131. 131. Within the same transac-on, how many persistence contexts should exist?
  132. 132. One persistence context In any given transac.on, we want exactly one persistence context (i.e., cache) for a given set of data Transaction | +-----------------------------------------------|-------------------------------------------------+ | | | | | | | +-----------------v-----------------+ | | | | | | | AccountService.transferFunds() | | | | | | | +-----------------+-----------------+ | | | | | | | | | | | | | | +---------------------------------------------------------------+ | | | | | | | | | | | | +------------v-----------+ +-----------v------------+ +-----------v-----------+ | | | | | | | | | | | AccountRepository | | AccountRepository | | LogRepository | | | | .update(account1) | | .update(account2) | | .create(entry) | | | | | | | | | | | +------------------------+ +------------------------+ +-----------------------+ | | | | | +-------------------------------------------------------------------------------------------------+
  133. 133. One persistence context By doing so, the different calls comprised in the transac3on will interact with the same data Transaction | +-----------------------------------------------|-------------------------------------------------+ | | | | | | | +-----------------v-----------------+ | | | | | | | AccountService.transferFunds() | | | | | | | +-----------------+-----------------+ | | | | | | | | | | | | | | +---------------------------------------------------------------+ | | | | | | | | | | | | +------------v-----------+ +-----------v------------+ +-----------v-----------+ | | | | | | | | | | | AccountRepository | | AccountRepository | | LogRepository | | | | .update(account1) | | .update(account2) | | .create(entry) | | | | | | | | | | | +------------------------+ +------------------------+ +-----------------------+ | | | | | +-------------------------------------------------------------------------------------------------+
  134. 134. One persistence context Therefore, we want exactly one EntityManger per transac3on, as different EntitManagers correspond to different persistence contexts
  135. 135. Persistence context propaga/on We want to automa&cally propagate the same persistence context to all the beans involved in the same transac5on @Repository public class AccountRepositoryImpl implements AccountRepository {...} @Repository public class LogRepositoryImpl implements LogRepository {...}
  136. 136. Persistence context propaga/on This amounts to injec/ng the same EntityManager to all the components involved @Repository public class JpaAccountRepository implements AccountRepository {...} @Repository public class JpaLogRepository implements LogRepository {...}
  137. 137. @PersistenceContext The @PersistenceContext annota)on automa&cally propagates the persistence context @Repository public class JpaAccountRepository implements AccountRepository { @PersistenceContext private EntityManager em; @Override public Account findById(int id) { return em.find(Account.class, id); } }
  138. 138. Mapping rela+onships
  139. 139. En##es and rela#onships If en&&es were isolated from one another, the issue of ORM would be a trivial one +------------+ +--------------+ | | | | | Employee | | Department | | | | | +------------+ +--------------+
  140. 140. En##es and rela#onships In reality, most en//es need to be able to have rela%onships with other en//es +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  141. 141. En##es and rela#onships This is what produces the domain model of the applica2on +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  142. 142. Rela%onships Every rela)onship has four characteris-cs • Direc'onality • Role • Cardinality • Ownership
  143. 143. Direc&onality Each en(ty in a rela(onship may have a pointer to the other en(ty +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  144. 144. Direc&onality If only one en)ty has a pointer to the other, the rela)onship is said to be unidirec(onal +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  145. 145. Direc&onality When each en(ty points to the other, the rela(onship is said to be bidirec'onal +------------+ +--------------+ | | | | | Employee <-------------> Department | | | * 1 | | +------------+ +--------------+
  146. 146. Direc&onality All rela'onships in JPA are unidirec(onal. A bidirec'onal rela'onship has to be intended as a pair of unidirec'onal mappings +------------+ * 1 +--------------+ | +-------------> | | Employee | | Department | | <-------------+ | +------------+ * 1 +--------------+
  147. 147. Role Depending on the direc.onality, we can iden.fy the en.ty playing the role of source and the en.ty playing the role of target +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  148. 148. Role Employee and Department are involved in a unidirec(onal rela(onship +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  149. 149. Role Employee is the source en)ty +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  150. 150. Role Department is the target en(ty +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  151. 151. Cardinality Each role in the rela-onship has its own cardinality • Many-to-one: many source en..es, one target en.ty • One-to-many: one source en.ty, many target en..es • One-to-one: one source en.ty, one target en.ty • Many-to-many: many source en..es, many target en..es
  152. 152. Ownership In the database, almost every rela2onship is implemented by introducing a column that refers to a key in another table
  153. 153. Ownership Such a column is usually called the join column
  154. 154. Ownership The underlying Employee table has a join column containing the Department primary key ┌─────────────┬───────────────┬─────────────┬──────────────┐ │ employeeId │ name │ gender │ departmentId │ ├─────────────┼───────────────┼─────────────┼──────────────┤ │ 12 │ Jon Snow │ male │ 7 │ └─────────────┴───────────────┴─────────────┴──────────────┘
  155. 155. Ownership The en&ty holding the join column is called the owner of the rela&onship and its side is called the owning side ┌─────────────┬───────────────┬─────────────┬──────────────┐ │ employeeId │ name │ gender │ departmentId │ ├─────────────┼───────────────┼─────────────┼──────────────┤ │ 12 │ Jon Snow │ male │ 7 │ └─────────────┴───────────────┴─────────────┴──────────────┘
  156. 156. Ownership Employee is the owner of the rela,onship +------------+ +--------------+ | | | | | Employee +-------------> Department | | | * 1 | | +------------+ +--------------+
  157. 157. Many-to-one mappings In a many-to-one mapping, the owner of the rela2onship is the source en2ty @Entity public class Employee { @Id private int id; @ManyToOne private Department department; }
  158. 158. Many-to-one mappings A many-to-one mapping is defined by annota2ng the source en)ty with the @ManyToOne annota2on @Entity public class Employee { @Id private int id; @ManyToOne private Department department; }
  159. 159. One-to-many mappings In a one-to-many mapping, the owner of the rela2onship is the target en2ty @Entity public class Department { @Id private int id; @OneToMany(mappedBy="department") private List<Employee> employees; }
  160. 160. One-to-many mappings Therefore, the @OneToMany annota,on must come with the mappedBy a3ribute @Entity public class Department { @Id private int id; @OneToMany(mappedBy="department") private List<Employee> employees; }
  161. 161. One-to-many mappings The mappedBy a&ribute indicates that the owning side resides at the other end of the rela5onship @Entity public class Department { @Id private int id; @OneToMany(mappedBy="department") private List<Employee> employees; }
  162. 162. One-to-one mappings In a one-to-one mapping, the owner can be either the source or the target en4ty @Entity public class Employee { @Id private int id; @OneToOne private ParkingSpace parkingSpace; }
  163. 163. One-to-one mappings A one-to-one mapping is defined by annota2ng the owner en'ty with the @OneToOne annota2on @Entity public class Employee { @Id private int id; @OneToOne private ParkingSpace parkingSpace; }
  164. 164. One-to-one mappings If the one-to-one mapping is bidirec4onal, the inverse side of the rela4onship needs to be specified as well @Entity public class ParkingSpace { @Id private int id; @OneToOne(mappedBy="parkingSpace") private Employee employee; }
  165. 165. One-to-one mappings In the non-owner en+ty, the @OneToOne annota+ons must come with the mappedBy element @Entity public class ParkingSpace { @Id private int id; @OneToOne(mappedBy="parkingSpace") private Employee employee; }
  166. 166. Many-to-many mappings In a many-to-many mapping there is no join column. The only way to implement such a mapping is by means of a join table ┌─────────────┬─────────────┐ │ employeeId │ projectId │ ├─────────────┼─────────────┤ │ 12 │ 7 │ ├─────────────┼─────────────┤ │ 1 │ 33 │ ├─────────────┼─────────────┤ │ 76 │ 7 │ └─────────────┴─────────────┘
  167. 167. Many-to-many mappings Therefore, we can arbitrarily specify as owner either the source or the target en6ty @Entity public class Employee { @Id private int id; @ManyToMany private List<Project> projects; }
  168. 168. Many-to-many mappings If the many-to-many mapping is bidirec5onal, the inverse side of the rela5onship needs to be specified as well @Entity public class Project { @Id private int id; @ManyToMany(mappedBy="projects") private List<Employee> employees; }
  169. 169. Many-to-many mappings In the non-owner en+ty, the @ManyToMany annota+on must come with the mappedBy element @Entity public class Project { @Id private int id; @ManyToMany(mappedBy="projects") private List<Employee> employees; }
  170. 170. Cascading opera.ons By default, every EntityManager’s opera2on applies only to the en2ty object supplied as the opera2on argument
  171. 171. Cascading opera.ons The opera)on will not cascade to other en))es that have a rela)onship with the en)ty that is being operated on
  172. 172. Cascading opera.ons For some opera*ons, this is usually the desired behavior // we do not want to also delete her department entityManager.remove(employ);
  173. 173. Cascading opera.ons For some other opera,ons, this is instead an unfortunate circumstances // we want to persist also the related department entityManager.persist(employ);
  174. 174. Cascading opera.ons If a transient en+ty has a rela+onship with another transient en+ty, the two must be persisted together
  175. 175. Manually cascading A naive approach would be to manually cascade related en33es Employee emp = new Employee(...); Department dep = new Department(...); emp.setDepartment(dep); entityManager.persist(dep); entityManager.persist(emp);
  176. 176. Manually cascading This is however inconvenient Employee emp = new Employee(...); Department dep = new Department(...); emp.setDepartment(dep); entityManager.persist(dep); entityManager.persist(emp);
  177. 177. Manually cascading We do not want to explicitly persist the Department instance Employee emp = new Employee(...); Department dep = new Department(...); emp.setDepartment(dep); entityManager.persist(dep); entityManager.persist(emp);
  178. 178. Cascading opera.ons The cascade a&ribute allows defining when opera5ons such as persist() should be automa&cally cascaded across rela5onships @Entity public class Employee { @ManyToOne(cascade=CascadeType.PERSIST) Department department; }
  179. 179. Cascading opera.ons The cascade a&ribute allows defining when opera5ons such as persist() should be automa&cally cascaded across rela5onships Employee emp = new Employee(...); Department dep = new Department(...); emp.setDepartment(dep); entityManager.persist(emp); // dep gets persisted as well
  180. 180. Cascading opera.ons You need to be sure that the Department instance has been set on the Employee instance before persist()-ing the la4er Employee emp = new Employee(...); Department dep = new Department(...); emp.setDepartment(dep); entityManager.persist(emp); // dep gets persisted as well
  181. 181. Cascading opera.ons The cascade a&ribute accepts several possible values coming from the CascadeType enumera4on • PERSIST, REFRESH, REMOVE, MERGE and DETACH
  182. 182. Cascading opera.ons The constant ALL is a shorthand for declaring that all five opera4ons should be cascaded @Entity public class Employee { @ManyToOne(cascade=CascadeType.ALL) Department department; }
  183. 183. Cascading opera.ons As with rela,onships, cascade se3ngs are unidirec(onal @Entity public class Employee { @Id private int id; @ManyToOne(cascade=CascadeType.PERSIST) Department department; } @Entity public class Department { @Id private int id; @OneToMany(cascade=CascadeType.PERSIST, mappedBy="department") private List<Employee> employees; }
  184. 184. Cascading opera.ons They must be explicitly set on both sides of a rela3onship if the same behavior is intended for both situa3ons @Entity public class Employee { @Id private int id; @ManyToOne(cascade=CascadeType.PERSIST) Department department; } @Entity public class Department { @Id private int id; @OneToMany(cascade=CascadeType.PERSIST, mappedBy="department") private List<Employee> employees; }
  185. 185. Lazy loading In many real situa.ons, certain por.ons of an en.ty will be seldom accessed +------------+ +--------------+ | | | | | Employee <-------------> Department | | | * 1 | | +------------+ +--------------+
  186. 186. Lazy loading Lazy loading is a design pa*ern that allows deferring the fetching of data un4l they are actually needed
  187. 187. Lazy loading The employees a&ribute may not be loaded each 3me a Department is loaded @Entity public class Department { @Id private int id; @OneToMany(fetch=FetchType.LAZY, ...) private List<Employee> employees; }
  188. 188. Lazy loading Lazy loading can improve performance because of the reduced amount of SQL that gets executed
  189. 189. Lazy loading In case of bidirec.onal rela.onships, the fetch mode might be lazy on one side but eager on the other @Entity public class Employee { @Id private int id; @ManyToOne Department department; } @Entity public class Department { @Id private int id; @OneToMany(mappedBy="department", fetch=FetchType.LAZY) private List<Employee> employees; }
  190. 190. Lazy loading As a ma&er of fact, rela/onships are o4en accessed in different ways depending on the direc/on from which naviga/on occurs @Entity public class Employee { @Id private int id; @ManyToOne Department department; } @Entity public class Department { @Id private int id; @OneToMany(mappedBy="department", fetch=FetchType.LAZY) private List<Employee> employees; }
  191. 191. Lazy loading Note that the direc,ve to lazily fetch an a/ribute is meant only to be a hint to the persistence provider @Entity public class Department { @Id private int id; @OneToMany(fetch=FetchType.LAZY, ...) private List<Employee> employees; }
  192. 192. Lazy loading The provider is not required to honor the request, as the behavior of the en4ty is not compromised if data get eagerly loaded @Entity public class Department { @Id private int id; @OneToMany(fetch=FetchType.LAZY, ...) private List<Employee> employees; }
  193. 193. Lazy loading The converse is not true: specifying that an a3ribute be eagerly fetched might be cri9cal to access the en9ty once detached @Entity public class Employee { @Id private int id; @ManyToOne Department department; }
  194. 194. Querying the data source
  195. 195. Querying the data source JPA provides three methods to retrieve en11es • EntityManager.find() • Query API • Criteria API
  196. 196. Query API
  197. 197. Java Persistence Query Language The Java Persistence Query Language (JPQL) is a pla0orm- independent object-oriented query language defined as part of the JPA specificaBon
  198. 198. Java Persistence Query Language The main difference with SQL is that • JPQL operates on classes and objects • SQL operates on tables, columns and rows
  199. 199. Java Persistence Query Language Therefore, the outcome of a JPQL query is a collec%on of objects, rather than a list of tuples
  200. 200. Java Persistence Query Language Note that JPQL syntax looks like SQL, but JPQL is not SQL SELECT e FROM Employee e
  201. 201. JQPL statements JPQL supports three types of statements • SELECT statements retrieve en,,es or en,ty-related data • UPDATE statements update one or more en,,es • DELETE statements delete one or more en,,es
  202. 202. FROM clause The FROM clause defines the domain for the query, that is, the en55es that will be used in the query SELECT e FROM Employee e
  203. 203. FROM clause Employee is the domain that we want to query, and e is intended as an iden(fier of type Employee SELECT e FROM Employee e
  204. 204. FROM clause Iden%fiers can be used in other clauses of the same query (e.g., WHERE clauses) SELECT e FROM Employee e WHERE e.name = "Jon Snow"
  205. 205. Path Expressions Given an iden)fier, we can use dot nota'on to access a specific field of the en)ty SELECT e FROM Employee e WHERE e.phones is NOT EMPTY
  206. 206. Path Expressions Such expressions are known as path expressions SELECT e FROM Employee e WHERE e.phones is NOT EMPTY
  207. 207. Path Expressions Path expressions are commonly used in • WHERE clauses so as to narrow the domain for a query • ORDER BY clauses so as to order the retrieved result set
  208. 208. JOIN operator In many common situa-ons, there is the need to join two or more en--es based on their rela-onship
  209. 209. JOIN operator To this end, joins can be specified either in the WHERE clause... SELECT p.number FROM Employee e, Phone p WHERE e = p.employee AND e.department.name = 'NA42'
  210. 210. JOIN operator ...or in the FROM clause by means of the JOIN operator SELECT p.number FROM Employee e JOIN e.phones p WHERE e.department.name = 'NA42'
  211. 211. Query API JPQL queries are executed by means of the Query API
  212. 212. Query API The required steps to create a JPA query are similar to those of a tradi7onal JDBC query ┌────────────────────────────────┬─────────────────────────────────────────┐ │///////////// JDBC /////////////│/////////////// Query API //////////////│ ├────────────────────────────────┼─────────────────────────────────────────┤ │ Obtain a database connection │ Obtain an EntityManager instance │ ├────────────────────────────────┼─────────────────────────────────────────┤ │ Create a query statement │ Create a query statement │ ├────────────────────────────────┼─────────────────────────────────────────┤ │ Execute the query │ Execute the query │ ├────────────────────────────────┼─────────────────────────────────────────┤ │ Retrieve the result (tuples) │ Retrieve the result (objects) │ └────────────────────────────────┴─────────────────────────────────────────┘
  213. 213. Query API The Query API supports two types of queries • Named queries, which are meant to be stored and reused • Dynamic queries, which are created and executed on the fly
  214. 214. Named query Named query are stored on the en'ty @Entity @NamedQuery( name = "findSalaries", query = "SELECT e.salary FROM Employee") public class Employee { ... }
  215. 215. Named query Any query that is used in mul$ple components of the applica4on is a candidate for a named query @Entity @NamedQuery( name = "findSalaries", query = "SELECT e.salary FROM Employee") public class Employee { ... }
  216. 216. Named query Named queries can enhance performance because they are prepared once and then efficiently reused @Entity @NamedQuery( name = "findSalaries", query = "SELECT e.salary FROM Employee") public class Employee { ... }
  217. 217. Named query Named query are globally scoped and instan/ated by name TypedQuery<Integer> query = entityManager .createNamedQuery("findSalaries");
  218. 218. Named query That is, named query instances can be created from any component that can access the persistence unit TypedQuery<Integer> query = entityManager .createNamedQuery("findSalaries");
  219. 219. Named query Consequently, a named queries must have a unique name in the whole persistence unit @Entity @NamedQuery(name = "findSalaries", query = "...") public class Employee { ... }
  220. 220. Dynamic query Dynamic queries are created at run 0me, and they are normally used when the query depends on the context String stmt = "SELECT e FROM Employee e WHERE e.name = :empName"; TypedQuery<Employee> query = entityManager.createQuery(stmt);
  221. 221. Dynamic query A dynamic query can be created wherever the EntityManager is available. The only requirement is to pass a valid JPQL statement String stmt = "SELECT e FROM Employee e WHERE e.name = :empName"; TypedQuery<Employee> query = entityManager.createQuery(stmt);
  222. 222. Execu&ng queries A TypedQuery object represents a query instance String stmt = "SELECT e FROM Employee e WHERE e.name = :empName"; TypedQuery<Employee> query = entityManager.createQuery(stmt);
  223. 223. Execu&ng queries The TypedQuery interface defines several methods for parameterizing and execu.ng the query ┌────────────────────────────────────────────┬─────────────────────────────────────────┐ │///////////// Method signature /////////////│////////////// Description //////////////│ ├────────────────────────────────────────────┼─────────────────────────────────────────┤ │ public List getResultList(); │ Retrieves the result set │ ├────────────────────────────────────────────┼─────────────────────────────────────────┤ │ public │ Sets the maximum number of objects to be│ │ TypedQuery<T> setMaxResults(int maxResult);│ retrieved │ ├────────────────────────────────────────────┼─────────────────────────────────────────┤ │ public │ │ │ TypedQuery<T> setParameter(int position, │ Sets the value for a positional │ │ Object value); │ parameter │ │ │ │ ├────────────────────────────────────────────┼─────────────────────────────────────────┤ │ public │ │ │ TypedQuery<T> setParameter(String name, │ Sets the value for a named parameter │ │ Object value); │ │ └────────────────────────────────────────────┴─────────────────────────────────────────┘
  224. 224. Parameters The number of en,,es retrieved in a query may be limited by specifying a WHERE clause, which can be parameterized SELECT e.salary FROM Employee e WHERE e.name = :empName
  225. 225. Parameters In JPA, There exist two types of parameters • Posi&onal parameters • Named parameters
  226. 226. Parameters Before execu*ng a query, all parameters need to be set SELECT e.salary FROM Employee e WHERE e.name = :empName
  227. 227. Parameters This can be done using the TypedQuery’s setParameter() method SELECT e.salary FROM Employee e WHERE e.name = :empName
  228. 228. Posi%onal parameters Posi%onal parameters are iden(fied by number String stmt = "SELECT i FROM Item i WHERE i.initialPrice = ?1"; TypedQuery<Item> query = em.createQuery(stmt); query.setParameter(1, 100.00); List<Item> items = query.getResultList();
  229. 229. Named parameters Named parameters are iden(fied by label String stmt = "SELECT i FROM Item i WHERE i.initialPrice = :price"; TypedQuery<Item> query = em.createQuery(stmt); query.setParameter("price", 100.00); List<Item> items = query.getResultList();
  230. 230. Criteria API
  231. 231. The problem with the Query API The Query API cannot verify the correctness of a JPQL query before its actual execu:on // This will compile despite the incorrect JQPL query TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee t");
  232. 232. The problem with the Query API We would much prefer to let the compila(on fail in the presence of incorrect JQPL queries
  233. 233. Criteria API The Criteria API provides a way of crea6ng type-safe queries, i.e., queries the compiler can check at compile-2me
  234. 234. Crea%ng a new query The steps for crea-ng a Criteria API-based query are 1. Obtaining a CriteriaBuilder object 2. Using this instance to compose a CriteriaQuery object 3. Execu9ng the query
  235. 235. Crea%ng a new query The CriteriaQuery instance represents the query we would like to execute
  236. 236. Crea%ng a new query The CriteriaBuilder interface provides methods for all keywords, operators, and func8ons from JPQL public interface CriteriaBuilder { CriteriaQuery<T> createQuery(Class<T> resultClass); Predicate and(Expression<Boolean> x, Expression<Boolean> y); Predicate or(Expression<Boolean> x, Expression<Boolean> y); Predicate isNotNull(Expression<?> x); ... }
  237. 237. Crea%ng a new query That is, the CriteriaBuilder is a factory for all the individual pieces of the query public interface CriteriaBuilder { CriteriaQuery<T> createQuery(Class<T> resultClass); Predicate and(Expression<Boolean> x, Expression<Boolean> y); Predicate or(Expression<Boolean> x, Expression<Boolean> y); Predicate isNotNull(Expression<?> x); ... }
  238. 238. Crea%ng a new query A CriteriaBuilder object can be obtained from an EntityManager instance CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  239. 239. Crea%ng a new query Once available, a CriteraBuilder can be used to create CriteriaQuery objects CriteriaQuery<Employee> c = cb.createQuery(Employee.class);
  240. 240. Crea%ng a new query To ensure type-safety, the CriteriaQuery's type parameter should be set to the result type of the query CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Employee> c = cb.createQuery(Employee.class);
  241. 241. Root object Every CriteriaQuery defines at least one Root object, whose role is analogous to that of an iden%fier in a JPQL query Root<Employee> e = c.from(Employee.class); c.select(e);
  242. 242. Root object Every CriteriaQuery defines at least one Root object, whose role is analogous to that of an iden%fier in a JPQL query SELECT e FROM Employee e
  243. 243. Root object Like JPQL iden+fiers, Root objects are commonly used in SELECT and WHERE clauses Root<Employee> e = c.from(Employee.class); c.select(e);
  244. 244. Canonical metamodel The Criteria API ensures type-safety by means of a canonical metamodel @StaticMetamodel(Employee.class) public class Employee_ {...} @StaticMetamodel(Department.class) public class Department_ {...} @StaticMetamodel(Project.class) public class Project_ {...}
  245. 245. Canonical metamodel The canonical metamodel of a persistence unit is a descrip1on of the persistent type, state, and rela1onships of en11es @StaticMetamodel(Employee.class) public class Employee_ {...} @StaticMetamodel(Department.class) public class Department_ {...} @StaticMetamodel(Project.class) public class Project_ {...}
  246. 246. Canonical metamodel In prac(ce, the canonical metamodel is implemented as a series of classes that mirror the en((es in the domain model @StaticMetamodel(Employee.class) public class Employee_ {...} @StaticMetamodel(Department.class) public class Department_ {...} @StaticMetamodel(Project.class) public class Project_ {...}
  247. 247. Canonical metamodel Such metamodel classes provide access to metadata about the associated domain class @StaticMetamodel(Employee.class) public class Employee_ { public static volatile SingularAttribute<Employee, Integer> id; public static volatile SingularAttribute<Employee, String> name; public static volatile SingularAttribute<Employee, String> salary; public static volatile SingularAttribute<Employee, Department> dept; public static volatile SingularAttribute<Employee, Address> address; public static volatile CollectionAttribute<Employee, Project> project; }
  248. 248. Canonical metamodel For each en*ty E, there should exist a metamodel class E_ in the same package @StaticMetamodel(Employee.class) public class Employee_ { public static volatile SingularAttribute<Employee, Integer> id; public static volatile SingularAttribute<Employee, String> name; public static volatile SingularAttribute<Employee, String> salary; public static volatile SingularAttribute<Employee, Department> dept; public static volatile SingularAttribute<Employee, Address> address; public static volatile CollectionAttribute<Employee, Project> project; }
  249. 249. Canonical metamodel Each metamodel class must be annotated with the @StaticMetamodel annota2on @StaticMetamodel(Employee.class) public class Employee_ { public static volatile SingularAttribute<Employee, Integer> id; public static volatile SingularAttribute<Employee, String> name; public static volatile SingularAttribute<Employee, String> salary; public static volatile SingularAttribute<Employee, Department> dept; public static volatile SingularAttribute<Employee, Address> address; public static volatile CollectionAttribute<Employee, Project> project; }
  250. 250. Path expressions Root objects and metamodel classes are employed together to form path expressions Root<Employee> e = c.from(Employee.class); c.select( e.get(Employee_.department).get(Department_.id) );
  251. 251. Path expressions The Root object and the metamodel classes are employed together to form path expressions SELECT e.department.id FROM Employee e
  252. 252. JOIN opera'on Joins can be performed by calling the join() method on the Root object Root<Employee> e = c.from(Employee.class); Join<Employee, Phone> p = e.join(Employee_.phones); c.select(p.get(Phone_.number)) c.where(cb.equal(e.get(Employee_.name), "Jon Snow"));
  253. 253. JOIN opera'on Joins can be performed by calling the join() method on the Root object SELECT p.number FROM Employee e JOIN e.phones p WHERE e.name = "Jon Snow"
  254. 254. JOIN opera'on Note that the resul,ng Join object behaves like a Root object, meaning that joins can be cascaded
  255. 255. WHERE clause WHERE clauses can be used to narrow the result set Root<Employee> e = c.from(Employee.class); c.select(e); c.where(cb.equal(e.get(Employee_.name), "Jon Snow"));
  256. 256. WHERE clause WHERE clauses can be used to narrow the result set SELECT e FROM Employee e WHERE e.name = "Jon Snow"
  257. 257. WHERE clause Each condi*on in a WHERE clause is expressed as a Predicate instance // Incremental construction Predicate predicates = cb.conjunction(); predicates = cb.and(predicates, cb.equal(e.get(Employee_.name), "Jon Snow")); predicates = cb.and(predicates, cb.equal(e.get(Employee_.dept).get(Department_.id), 7)); c.where(predicates);
  258. 258. WHERE clause Predicates can be combined by means of AND or OR operators // Incremental construction Predicate predicates = cb.conjunction(); predicates = cb.and(predicates, cb.equal(e.get(Employee_.name), "Jon Snow")); predicates = cb.and(predicates, cb.equal(e.get(Employee_.dept).get(Department_.id), 7)); c.where(predicates);
  259. 259. WHERE clause Predicates can be combined by means of AND or OR operators // List-based construction List<Predicate> predicates = new ArrayList<>(); predicates.add(cb.equal(e.get(Employee_.name), "Jon Snow")); predicates.add(cb.equal(e.get(Employee_.dept).get(Department_.id), 7)); Predicate[] predArray = predicates.toArray(new Predicate[predicates.size()]); c.where(cb.and(predArray));
  260. 260. WHERE clause Predicates can be combined by means of AND or OR operators SELECT e FROM Employee e WHERE e.name = "Jon Snow" AND d.department.id = 7
  261. 261. Defining parameters To parameterize queries using the Criteria API, a ParameterExpression object must be created ParameterExpression<String> deptName = cb.parameter(String.class, "deptName");
  262. 262. Execu&ng queries Once the query is composed, it is possible to obtain a TypedQuery object out of a CriteriaQuery object TypedQuery<Employee> q = entityManager.createQuery(c);
  263. 263. Execu&ng queries As with any TypedQuery, parameters need to be provided before the actual execu9on TypedQuery<Employee> q = em.createQuery(c); q.setParameter("deptName", "NA42") return q.getResultList();
  264. 264. References
  265. 265. References • Java Community Process, JPA 2.1 specifica:on • Hibernate Community Documenta:on, EntityManager • Hibernate Community Documenta:on, Transac:ons and Concurrency • Wikipedia, Data Access Object • SpringSource, Spring Framework Reference
  266. 266. References • Hibernate Wiki, Data Access Objects • Hibernate Wiki, Open Session in View pa9ern • Hibernate Community Documenta>on, Metamodel • Hibernate Community Documenta>on, Criteria Queries • OpenJPA, JPA Concepts
  267. 267. References • M. Keith, M. Schincariol, Pro JPA 2, Mastering The Java Persistence API, Apress Media LLC • D. Panda et al., EJB3 In AcCon, Manning PublicaCons • C. Baver, G.King, Java Persistence With Hibernate, Manning PublicaCons • S. Guruzu, G. Mak, Hibernate Recipes - A Problem-SoluCon Approach, Apress Media LLC
  268. 268. References • A.L. Rubinger, B.Burke, Enterprise JavaBeans 3.1, O’Reilly Media • R.M. Reese, EJB 3.1 Cookbook, Packt Publishing • Craig Walls, Spring in AcGon (3rd EdiGon), Manning PublicaGons • Willie Wheeler, Spring in PracGce, Manning PublicaGons
  269. 269. Topics not covered • Physical annota.ons • Cascading policies other than PERSIST • Vender-based APIs (e.g., Hibernate APIs) • Advanced JPQL and Criteria API-based queries • Long units of work

×