2. GOAL OF THE
PRESENTATION
give a good overview of the Java Persistence API (JPA),
while still addressing more advanced issues & common pitfalls
all you need to successfully start with JPA
3. So... You are still not using JavaEE 5 ?
Still stuck with a RDBMS ?
Still believe JDBC is fun ?
4. try {
Connection connection =
DriverManager.getConnection(quot;jdbc:derby:Console;create=truequot;);
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(quot;SELECT first_name, last_name FROM personsquot;);
ResultSet resultSet = null;
try {
resultSet = statement.getResultSet();
while(resultSet.next()) {
String fName = resultSet.getString(quot;first_namequot;);
System.out.println(resultSet.wasNull ? quot;(null)quot; : fName);
}
} catch (SQLException e) {
// Handle exception thrown while retrieving the result
} finally {
if(resultSet != null)
resultSet.close();
}
} catch (SQLException e) {
// Handle exception thrown while trying to get to the database
} finally {
if(statement != null)
statement.close();
connection.close();
}
} catch (SQLException e) {
// Handle exception thrown while trying to get a connection
}
5. OBJECT RELATIONAL MAPPING
Eliminates the need for JDBC
•
CRUD & Querying
•
Object identity management
•
Inheritance strategies
•
Class hierarchy to single or multiple tables
•
Associations, Composition
•
Lazy navigation
•
Fetching strategies
•
6. INTRODUCING JPA
• Vendor independent ORM solution
• Easily configurable
• Configuration directly in code using Java 5 annotations
• Configuration fine tunable,
overriding annotations using XML
• Available outside JavaEE containers
• Dedicated Java Specification Request
JSR 317 as of JPA 2.0
7. last thing on ORM :
• One
It should all be ... transparent!
”The effective use of ORM technology in all but the
simplest of enterprise environments requires
understanding and configuring how the mediation
between relational data and objects is performed”
Linda DeMichiel
Lead Architect EJB, Sun
9. JPA – BACK TO POJOS
• Transparent yet:
• Non-final class or methods
• Constructor with no argument
• Collections typed to interfaces
• Associations aren’t managed for you
• Database identifier field
10. SIMPLEST ENTITY EXAMPLE
@Entity
public class Person {
@Id
private Long ssn;
private String firstName;
private String lastName;
protected Person() {}
public Person(Long ssn, String firstName, String lastName) {
...
}
}
11. SIMPLE STILL, BUT VERBOSE
@Entity(name = “Humans”)
@Table(name = “persons”, schema = “hr”)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Basic
private Long ssn;
private String firstName;
@Column(name = quot;NAMEquot;, unique = false, nullable = false, length = 255)
private String lastName;
protected Person() {}
public Person(Long ssn, String firstName, String lastName) {
...
}
}
13. CLASS HIERARCHIES
• Entities support
• Inheritance
• polymorphic associations
• Concrete and abstract can be mapped
• @Entity
• @MappedSuperclass
14. POLYMORPHISM
• Three mapping strategies
• One table per class hierarchy
• Joined subclass
• One table per concrete class (optional)
15. MANY-TO-ONE
ASSOCIATIONS
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long ssn;
private String firstName;
private String lastName;
@JoinColumn(name = “ID_COMP”)
@ManyToOne
private Company company;
protected Person() {}
public Person(Long ssn, String firstName, String lastName) {
...
}
}
16. MANY-TO-ONE
ASSOCIATIONS
Person
Company
- id: Long
1
- ssn: Long - id: Long
- firstName: String - name: String
- lastName: String
person company
PK id PK id
ssn name
firstname
lname
FK1 company_id
17. ONE-TO-ONE ASSOCIATIONS
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long ssn;
private String firstName;
private String lastName;
@OneToOne
private AccessPass accessPass;
protected Person() {}
public Person(Long ssn, String firstName, String lastName) {
...
}
}
18. ONE-TO-ONE ASSOCIATIONS
Person
AccessPass
- id: Long
0..1
- ssn: Long - id: Long
- firstName: String - validUntil: Date
- lastName: String
person access
PK id PK id
ssn until
firstname
lname
FK1 access_id
19. ONE-TO-ONE
BI-DIRECTIONAL
@Entity
public class AccessPass {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Temporal(TemporalType.DATE)
private Date validUntil;
@OneToOne(mappedBy=”accessPass”)
private Person owner;
protected AccessPass() {}
public Person(Person person, Date validUntil) {
this.person = person;
this.validUntil = (Date) validUntil.clone();
}
}
20. ONE-TO-MANY
BI-DIRECTIONAL
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = ”resident”)
private Set<Address> addresses = new HashSet<Address>();
protected Person() {}
}
21. ONE-TO-MANY
BI-DIRECTIONAL
@Entity
public class Address {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne @JoinColumn(name = “resident_id”)
private Person resident;
public Address() {}
public void setResident(Person resident) {
if(this.resident != resident) {
if(this.resident != null)
resident.removeAddress(this);
this.resident = resident;
if(resident != null)
resident.addAddress(this);
}
}
}
22. ONE-TO-MANY
BI-DIRECTIONAL
@Entity
public class Person {
...
@OneToMany(mappedBy = ”resident”)
private Set<Address> addresses = new HashSet<Address>();
public void addAddress(Address address) {
if(!this.addresses.contains(address)) {
this.addresses.add(address);
address.setResident(this);
}
}
public void removeAddress(Address address) {
if(this.addresses.contains(address)) {
this.addresses.remove(address);
address.setResident(null);
}
}
}
23. ONE-TO-MANY
UNI-DIRECTIONAL
• Same as the bi-directional only without the mappedBy
• Without a owning side with cardinality of one,
a join table is required!
person_address
person address
FK1 person_id
PK id PK id
FK2 address_id
... ...
• With a unique constraint on FK2
• Many-to-Many is equal to One-to-Many uni-directional,
but without the unique constraint
24. *-TO-MANY EXAMPLES
@Entity
public class Person {
...
@OneToMany
private Set<Address> addresses = new HashSet<Address>();
@ManyToMany(cascade = CascadeType.ALL)
private Set<Project> projects = new HashSet<Project>();
...
@OneToMany(mappedBy = “owner”)
@MapKey(name = “type”)
private Map<String, PhoneNumber> phones = new HashMap<String, PhoneNumber>();
}
26. MANAGING PERSISTENCE
• javax.persistence.Persistence
creates an EntityManagerFactory
based on a persistence unit name
• Withthe EntityManagerFactory instance,
you create EntityManager instances
to handle
• EntityManager
the persistence of your entities
to... query(!) them back from the database
• Query
used for transaction demarcation
• EntityTransaction
27. SETTING UP
THE PERSISTENCE UNIT
<persistence xmlns=quot;http://java.sun.com/xml/ns/persistencequot;
version=quot;1.0quot;>
<persistence-unit name=quot;myPUquot;>
<jta-data-source>
jdbc/myIncredibleDS
</jta-data-source>
</persistence-unit>
</persistence>
28. SETTING UP
THE PERSISTENCE UNIT
<persistence-unit name=quot;myPUquot;
transaction-type=quot;RESOURCE_LOCALquot;>
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<class>some.domain.Class</class>
<properties>
<property name=quot;toplink.jdbc.driverquot;
value=quot;org.apache.derby.jdbc.EmbeddedDriverquot;/>
<property name=quot;toplink.jdbc.urlquot;
value=quot;jdbc:derby:myData;create=truequot;/>
<property name=quot;toplink.ddl-generationquot;
value=quot;create-tablesquot;/>
</properties>
29. DEPENDENCY INJECTION
@Stateless
public class EmployeeDaoBean
implements EmployeeDao {
@PersistenceContext(unitName = “myPU”)
private EntityManager em;
public Person getEmployee(Long ssn) {
return em.find(Person.class, ssn);
}
}
30. THE ENTITYMANAGER
• Manages object identity
• Manages CRUD operations
EntityManager.find(Class<T>, Object): T
•
EntityManager.persist(Object): void
•
EntityManager.remove(Object): void
•
• Now how do I update ?
• You DO NOT!
32. THE LIFE-CYCLE
• An entity can be described to be in four states
• New: the entity instance is new and
not yet associated to a persistence context;
• Managed: the entity instance is associated
to a persistence context;
• Detached: the entity has a persistent identity, but is not
(anymore) associated to a persistence context;
• Removed: the entity has a persistent identity & is
associated to a persistence context,
but scheduled for removal.
33. PERSISTING AN ENTITY
• The operation EntityManager.persist(Object)
will have a new entity instance to become managed;
• Other entities referenced by the entity, whose association
are to be cascaded when persisting, will also be persisted;
• Ifalready managed, the operation will be ignored, but might be
cascaded to other entities referenced by it.
• Yet, this might not happen as you call persist on the entity!
34. REMOVING AN ENTITY
• Youschedule the removal of an entity by calling
EntityManager.remove(Object) operation
• Ifthe entity is new or already scheduled for removal,
the operation is ignored
• Again the operation might be cascaded
• Actual delete can be the result of the transaction committing
or an explicit flush() of the persistence context
35. MANAGED ENTITIES
•A managed entity will have its state automatically synchronized
with the database.
• This
operation, called flushing,
depends on the flush mode
Auto, or
•
Commit
•
• In
the FlushModeType.COMMIT, the entity’s state will
only be synchronized when the transaction actually commits
• This is not the default behavior of a PersistenceContext
36. AUTO FLUSH MODE
• Inthe FlushModeType.AUTO, the entity’s state will still be
synchronized to the database at the latest when the
transaction commits or when ...
•A transaction is active and
• Either you flush with EntityManager.flush();
• or an operation requires the state to be synched.
38. @PersistenceContext
private EntityManager em;
public void methodWithTxDemarcation() {
// loads Company named Apple Computers
Company company = em.find(Company.class, quot;AAPLquot;);
company.setName(quot;Apple Inc.quot;);
Company newCompany = new Company(quot;Sun Microsystemsquot;, quot;JAVAquot;);
em.persist(newCompany);
Query query = em.createQuery(quot;select c from Companiesquot;);
List list = query.getResultList();
}
39. @Stateful
@TransactionAttribute(NOT_SUPPORTED)
public class StatefulBean {
@PersistenceContext (type = EXTENDED)
private EntityManager em;
public void createTheSun() {
Company newCompany = new Company(quot;Sun Microsystemsquot;, quot;JAVAquot;);
em.persist(newCompany);
}
public List<Company> query() {
Query query = em.createQuery(quot;select c from Companiesquot;);
List list = query.getResultList();
return list;
}
@TransactionAttribute(REQUIRED)
@Remove
public void done() {
}
}
40. DETACHED ENTITIES
• An entity is detached when
• its persistence context is closed;
• In a JavaEE environment,
defaults when the transaction commits;
• In a JavaSE environment,
you manage the persistence context’s life-cycle.
• the entity is serialized;
• an exception occurred !
41. MERGING
DETACH ENTITIES BACK
• Youcan merge an entity back with a persistent context using
EntityManager.merge(Object): Object
• Ifentity is detached, a new managed instance of the entity is
returned, with the detached copied into it;
• Ifthe entity is new, a new managed entity is returned, after
have the state copied into it;
• Again, cascading applies;
• Ifthe entity is scheduled for removal,
an Exception is thrown.
42. OPTIMISTIC LOCKING
• Toenable optimistic locking on an entity,
simply annotate an entity field with @Version
• Theversion attribute will be updated by the EntityManager
every time the entity’s state is written to the database
• Field can be of type :
int, Integer, short, Short, long, Long, Timestamp
• Apply it consistently to graphs
• Do not modify it...
• Throws OptimisticLockException
44. JPA QUERY LANGUAGE
• The Query API
• is used for
• named queries
• dynamic queries
• supports
• polymorphism
• named parameters
• pagination
45. DYNAMIC QUERIES
em.createQuery(
quot;SELECT c FROM Customer c WHERE c.namequot;
+ quot; LIKE :custNamequot;)
.setParameter(quot;custNamequot;, name)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
46. STATIC QUERIES
@NamedQuery(
name =quot;findAllCustomersWithNamequot;,
query=quot;SELECT c FROM Customer c
WHERE c.name LIKE :custNamequot;)
47. BULK OPERATIONS
• Youcan bulk update & delete operations
with the Query API
• Delete example:
DELETE FROM Customer c
WHERE c.status = ‘inactive’
• Update example:
UPDATE customer c
SET c.status = ‘outstanding’
WHERE c.balance < 10000 AND 1000 >
(SELECT COUNT(o)
FROM customer cust JOIN cust.order o)
50. OBJECT IDENTITY
• How do you deal with object equality ?
• Introduce the database identifier as part of it ?
• Quick reminder from java.lang.Object#equals(Object)
Note that it is generally necessary to override the hashCode
method whenever this method is overridden, so as to maintain
the general contract for the hashCode method, which states that
equal objects must have equal hash codes.
51. OBJECT IDENTITY
• So that if the database identifier is in it,
you always have to have it assigned before
using it in a Collection for instance
Company company = new
Company(“JoGoSlow”);
em.persist(company);
em.flush();
group.addCompany(company);
52. OBJECT IDENTITY
• Other possible solutions
• Have real business key
• Have some sort of GUID / UUID
• Do not override equals(Object) nor hashCode()
except if you real need to & know what you are doing !
• Yet that isn’t okay if your object
is to be used as composite identifier
54. GETTING AN
ENTITYMANAGER
• In JavaEE
• Using dependency injection:
@PersistenceContext
EntityManager em;
• Getting the EntityManagerFactory
@PersistenceUnit
EntityManagerFactory emf;
• Within a SFSB
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager orderEM;
55. EXTENDED
PERSISTENCE CONTEXT
• To be used within a Stateful SessionBean
• Thepersistence context will be created,
when the SFSB is himself created
• And will be closed when the SFSB and all other SFSB that
inherited the Persistence Context have been removed
• Ifthe SFSB uses container-managed transaction demarcation,
the persistence context will join the tx
57. MORE FLEXIBLE MODELING
AND MAPPING
• Collections of basic types
• Improved support for embeddable classes
• Ordered lists
• Generalized maps
• Expanded relationship mapping options
• More flexible use of access types
60. SUMMARY
• JPA makes dealing with RDBMS simpler
• ... once you’ve understood how it works!
• It is available in JavaEE and JavaSE
• Multiple vendors
• On going dedicated JSR
with lots of improvement on its way
• Great tool support
61. CONCLUDING STATEMENT
So you think you want to forget about JDBC ?
The Java Persistence API looks cool ?
It all can be yours today... and with great tooling !