63
KICK START JPA Alexander Snaps – Axen

Kick Start Jpa

Embed Size (px)

Citation preview

Page 1: Kick Start Jpa

KICK START JPAAlexander Snaps – Axen

Page 2: Kick Start Jpa

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

Page 3: Kick Start Jpa

So... You are still not using JavaEE 5 ?

Still believe JDBC is fun ?Still stuck with a RDBMS ?

Page 4: Kick Start Jpa

try { Connection connection = DriverManager.getConnection("jdbc:derby:Console;create=true"); Statement statement = null; try { statement = connection.createStatement(); statement.execute("SELECT first_name, last_name FROM persons"); ResultSet resultSet = null; try { resultSet = statement.getResultSet(); while(resultSet.next()) { String fName = resultSet.getString("first_name"); System.out.println(resultSet.wasNull ? "(null)" : 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}

Page 5: Kick Start Jpa

• 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

OBJECT RELATIONAL MAPPING

Page 6: Kick Start Jpa

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 RequestJSR 317 as of JPA 2.0

Page 7: Kick Start Jpa

• One last thing on ORM

”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

It should all be ... transparent!:

Page 8: Kick Start Jpa

MAPPINGS

Page 9: Kick Start Jpa

• Transparent yet:

• Non-final class or methods

• Constructor with no argument

• Collections typed to interfaces

• Associations aren’t managed for you

• Database identifier field

JPA – BACK TO POJOS

Page 10: Kick Start Jpa

SIMPLEST ENTITY EXAMPLE@Entitypublic class Person { @Id

private Long ssn; private String firstName;

private String lastName; protected Person() {}

public Person(Long ssn, String firstName, String lastName) {

...

}}

Page 11: Kick Start Jpa

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 = "NAME", unique = false, nullable = false, length = 255)

private String lastName;

protected Person() {}

public Person(Long ssn, String firstName, String lastName) {

...

}}

Page 12: Kick Start Jpa

SIMPLE TYPES• Primitives & wrapper classes !

• java.lang.String !

• java.math.BigInteger & BigDecimal

• Byte & Character arrays

• Java & JDBC Temporal types

• Enumeration

• Serializable types

Page 13: Kick Start Jpa

CLASS HIERARCHIES

• Entities support

• Inheritance

• polymorphic associations

• Concrete and abstract can be mapped

• @Entity

• @MappedSuperclass

Page 14: Kick Start Jpa

POLYMORPHISM

• Three mapping strategies

• One table per class hierarchy

• Joined subclass

• One table per concrete class (optional)

Page 15: Kick Start Jpa

MANY-TO-ONE ASSOCIATIONS

@Entitypublic class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

private Long ssn; private String firstName; private String lastName;

private Company company; protected Person() {}

public Person(Long ssn, String firstName, String lastName) {

...

}}

@JoinColumn(name = “ID_COMP”) @ManyToOne

Page 16: Kick Start Jpa

MANY-TO-ONE ASSOCIATIONS

Person

- id: Long

- ssn: Long

- firstName: String

- lastName: String

Company

- id: Long

- name: String1

FK1

ssn

firstname

lname

company_id

PK id

person

name

PK id

company

Page 17: Kick Start Jpa

ONE-TO-ONE ASSOCIATIONS

@Entitypublic 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) {

...

}}

Page 18: Kick Start Jpa

ONE-TO-ONE ASSOCIATIONS

Person

- id: Long

- ssn: Long

- firstName: String

- lastName: String

AccessPass

- id: Long

- validUntil: Date0..1

FK1

ssn

firstname

lname

access_id

PK id

person

until

PK id

access

Page 19: Kick Start Jpa

ONE-TO-ONEBI-DIRECTIONAL

@Entitypublic 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(); }}

Page 20: Kick Start Jpa

ONE-TO-MANYBI-DIRECTIONAL

@Entitypublic class Person {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

@OneToMany(mappedBy = ”resident”) private Set<Address> addresses = new HashSet<Address>();

protected Person() {} }

Page 21: Kick Start Jpa

ONE-TO-MANYBI-DIRECTIONAL

@Entitypublic 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); } } }

Page 22: Kick Start Jpa

ONE-TO-MANYBI-DIRECTIONAL

@Entitypublic 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); } } }

Page 23: Kick Start Jpa

ONE-TO-MANYUNI-DIRECTIONAL

• Same as the bi-directional only without the mappedBy

• Without a owning side with cardinality of one, a join table is required!

FK1

FK2

person_id

address_id

person_address

...

PK id

address

...

PK id

person

• With a unique constraint on FK2

• Many-to-Many is equal to One-to-Many uni-directional, but without the unique constraint

Page 24: Kick Start Jpa

*-TO-MANY EXAMPLES

@Entitypublic 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>();}

Page 25: Kick Start Jpa

USING JPA ENTITIES

Page 26: Kick Start Jpa

MANAGING PERSISTENCE

• javax.persistence.Persistence creates an EntityManagerFactory based on a persistence unit name

• With the EntityManagerFactory instance,you create EntityManager instances

• EntityManager to handle the persistence of your entities

• EntityTransaction used for transaction demarcation

• Query to... query(!) them back from the database

Page 27: Kick Start Jpa

SETTING UPTHE PERSISTENCE UNIT

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

<persistence-unit name="myPU">

<jta-data-source> jdbc/myIncredibleDS </jta-data-source>

</persistence-unit>

</persistence>

Page 28: Kick Start Jpa

SETTING UPTHE PERSISTENCE UNIT

<persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL">

<provider> oracle.toplink.essentials.PersistenceProvider </provider> <class>some.domain.Class</class> <properties> <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/> <property name="toplink.jdbc.url" value="jdbc:derby:myData;create=true"/> <property name="toplink.ddl-generation" value="create-tables"/> </properties>

Page 29: Kick Start Jpa

DEPENDENCY INJECTION@Statelesspublic class EmployeeDaoBean implements EmployeeDao {

@PersistenceContext(unitName = “myPU”) private EntityManager em;

public Person getEmployee(Long ssn) { return em.find(Person.class, ssn); }}

Page 30: Kick Start Jpa

THE ENTITYMANAGER

• EntityManager.remove(Object): void

• EntityManager.find(Class<T>, Object): T

• EntityManager.persist(Object): void

• Manages CRUD operations

• Now how do I update ?

• You DO NOT!

• Manages object identity

Page 31: Kick Start Jpa

ENTITY LIFE-CYCLE

Page 32: Kick Start Jpa

THE LIFE-CYCLE• An entity can be described to be in four states

• Removed: the entity has a persistent identity & is associated to a persistence context, but scheduled for removal.

• Detached: the entity has a persistent identity, but is not (anymore) associated to a persistence context;

• Managed: the entity instance is associated to a persistence context;

• New: the entity instance is new and not yet associated to a persistence context;

Page 33: Kick Start Jpa

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;

• If already 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!

Page 34: Kick Start Jpa

REMOVING AN ENTITY

• You schedule the removal of an entity by calling EntityManager.remove(Object) operation

• If the 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

Page 35: Kick Start Jpa

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

Page 36: Kick Start Jpa

AUTO FLUSH MODE

• In the 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.

Page 37: Kick Start Jpa

SOME EXAMPLE

Page 38: Kick Start Jpa

public void methodWithTxDemarcation() {

// loads Company named Apple Computers Company company = em.find(Company.class, "AAPL"); company.setName("Apple Inc.");

}

Query query = em.createQuery("select c from Companies"); List list = query.getResultList();

Company newCompany = new Company("Sun Microsystems", "JAVA"); em.persist(newCompany);

@PersistenceContextprivate EntityManager em;

Page 39: Kick Start Jpa

@Stateful@TransactionAttribute(NOT_SUPPORTED)public class StatefulBean {

public void createTheSun() {

}

public List<Company> query() {

return list; }

@TransactionAttribute(REQUIRED)@Removepublic void done() {}

}

Query query = em.createQuery("select c from Companies"); List list = query.getResultList();

Company newCompany = new Company("Sun Microsystems", "JAVA"); em.persist(newCompany);

@PersistenceContextprivate EntityManager em;

(type = EXTENDED)

Page 40: Kick Start Jpa

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 !

Page 41: Kick Start Jpa

MERGINGDETACH ENTITIES BACK

• You can merge an entity back with a persistent context using EntityManager.merge(Object): Object

• If entity is detached, a new managed instance of the entity is returned, with the detached copied into it;

• If the entity is new, a new managed entity is returned, after have the state copied into it;

• Again, cascading applies;

• If the entity is scheduled for removal, an Exception is thrown.

Page 42: Kick Start Jpa

OPTIMISTIC LOCKING• To enable optimistic locking on an entity,

simply annotate an entity field with @Version

• The version 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

Page 43: Kick Start Jpa

QUERIES & BULK OPERATIONS

Page 44: Kick Start Jpa

JPA QUERY LANGUAGE• The Query API

• is used for

• named queries • dynamic queries

• supports

• polymorphism• named parameters• pagination

Page 45: Kick Start Jpa

DYNAMIC QUERIES

em.createQuery( "SELECT c FROM Customer c WHERE c.name" + " LIKE :custName") .setParameter("custName", name) .setFirstResult(10) .setMaxResults(10) .getResultList();

Page 46: Kick Start Jpa

STATIC QUERIES

@NamedQuery( name ="findAllCustomersWithName", query="SELECT c FROM Customer c WHERE c.name LIKE :custName")

Page 47: Kick Start Jpa

BULK OPERATIONS• You can 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)

Page 48: Kick Start Jpa

BULK OPERATIONS

Caution !Bulk operation will not affect the EntityManager !!!

Page 49: Kick Start Jpa

OBJECT IDENTITYVS.

DATABASE IDENTITY

Page 50: Kick Start Jpa

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.

Page 51: Kick Start Jpa

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);

Page 52: Kick Start Jpa

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

Page 53: Kick Start Jpa

JPA IN A JAVA EE ENVIRONMENT

Page 54: Kick Start Jpa

GETTING AN ENTITYMANAGER

• In JavaEE

• Using dependency injection:@PersistenceContext EntityManager em;

• Within a SFSB@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager orderEM;

• Getting the EntityManagerFactory@PersistenceUnit EntityManagerFactory emf;

Page 55: Kick Start Jpa

EXTENDEDPERSISTENCE CONTEXT

• To be used within a Stateful SessionBean

• The persistence 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

• If the SFSB uses container-managed transaction demarcation, the persistence context will join the tx

Page 56: Kick Start Jpa

JPA 2.0aka. JSR 317

Page 57: Kick Start Jpa

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

Page 58: Kick Start Jpa

CRITERIA APICriteria crit = new Criteria(User.class) .project(Name.class) .property("firstName") .property("lastName") .orderBy() .property("lastName").asc() .property("firstName").asc() .property("age").desc() .restrict() .property("name").eq("Gavin") .and() .property("age").gt(18) .fetch("dependents").leftJoin() .join("address") .restrict() .property("country").in("USA", "AUSTRALIA");

em.createQuery(crit).getResultList();

Page 59: Kick Start Jpa

WELL ...

Page 60: Kick Start Jpa

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

Page 61: Kick Start Jpa

CONCLUDING STATEMENTSo you think you want to forget about JDBC ?

The Java Persistence API looks cool ?It all can be yours today... and with great tooling !

Page 62: Kick Start Jpa

& answers?Questions

Page 63: Kick Start Jpa

THANKS FOR YOUR ATTENTION!

[email protected]