Java Persistence API (JPA)


Creative Commons License
This Java Persistence API (JPA) tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Preamble
This tutorial is about the Java Persistence Application Programming Interface. JPA is a Java SE technology (see API here).
Case studies are provided as NetBeans projects; they have also been tested by means of this IDE (Integrated Development Environment).
What is JPA?
JPA engine most famous implementations
Packages
Case study
The notion of POJO (a.k.a. Entity Beans in Java EE)
Getting a persistence manager
Entity Beans can be managed through a persistence manager only
Entity Bean lifecycle
Entity Beans lifecycle
Entity Bean states
Key operations on Entity Beans
Synchronizing with Entity Bean lifecycle
Key operations on the global pool of Entity Beans
Transaction management

Transaction support

A transaction support is injected as resource as follows (BMT standing for Bean-Managed Transaction):

@javax.annotation.Resource
private javax.transaction.UserTransaction _userTransaction; // No instantiation required!


JTS (standing for Java Transaction Service) is by default enabled in the persistence unit; it can be disabled as follows:

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

<non-jta-data-source>jdbc/NYCP</non-jta-data-source>

</persistence-unit>


Managing transactions manually is based on the following:

private javax.persistence.EntityTransaction _entityTransaction = _entityManager.getTransaction(); // Transactions are managed in the Bean-Managed Transaction mode (Java SE for instance)

Dealing with transactions (Bean-Managed Transaction mode)...

Transaction-scoped persistence context (javax.persistence.PersistenceContextType.TRANSACTION):

_userTransaction.begin(); // '_entityManager' is enabled
_entityManager.persist(prisoner);
assert (_entityManager.contains(prisoner) == true);
_userTransaction.commit(); // '_entityManager' is disabled


Extended persistence context (javax.persistence.PersistenceContextType.EXTENDED):

_userTransaction.begin();
_entityManager.joinTransaction();
_entityManager.persist(prisoner); // It may also be called outside a transaction scope
_userTransaction.commit();
Constructing Entity Beans
Building a JPA application or simple module is mostly concerned with creating Entity Beans that map to tables in a database. However, this mapping has not to be, in any case, a one-to-one mapping, i.e., 1 table does not systematically amount to 1 and only 1 Entity Bean
The mapping is thus ruled by creation processes, key and recurrent navigation between objects, performance with suitable dependency loading (lazy or eager modes)

Constraints (not illustrated in examples below)

Simple Entity Bean

Basic annotations

Example:

@javax.persistence.Entity(name = "My_prisoner") // Class name by default when 'name' is not used
@javax.persistence.Table(name = "Prisoner") // It is optional when the table name is equal to the Java class name
public class Prisoner implements java.io.Serializable { …

Persistent field

Temporal persistent field

Fields of type java.util.Date or java.util.Calendar must be annotated with @javax.persistence.Temporal:

@javax.persistence.Column(name = "DATE_OF_INCARCERATION")
@javax.persistence.Temporal(javax.persistence.TemporalType.DATE)
private java.util.Date _date_of_incarceration;

Enumerated persistent field

Fields of type enum in Java may be used in conjunction with JPA with the help of @javax.persistence.Enumerated

Java:

public enum Fire_truck_statuses {Idle, Dispatched, Arrived , Blocked, Breakdown}

JPA:

@javax.persistence.Column(name = "FIRE_TRUCK_STATUS")
@javax.persistence.Enumerated(javax.persistence.EnumType.STRING)
private Fire_truck_statuses _fire_truck_status;

SQL:

create table BCMS_session_Fire_truck(

FIRE_TRUCK_STATUS varchar(10) constraint FIRE_TRUCK_STATUS_CHECK check (fire_truck_status IN ('Idle', 'Dispatched', 'Arrived', 'Blocked', 'Breakdown')),

Embeddable and embedded Entity Beans

Embeddable Entity Beans do not map to tables. Instead, they later become field types in enclosing Entity Beans:

@javax.persistence.Embeddable
public class Address implements java.io.Serializable {

@javax.persistence.Column(name = "ZIP_CODE", length = 5)
private String _zip_code;


@javax.persistence.Entity // Table name must be 'Customer'
public class Customer implements java.io.Serializable {

@javax.persistence.Embedded
@javax.persistence.AttributeOverrides({@javax.persistence.AttributeOverride(name = "_zip_code", column = @javax.persistence.Column(name = "ZIP_CODE_OF_CUSTOMER_INVOICING_ADDRESS"))})
private Address _invoicing_address;

@javax.persistence.Embedded
private Address _shipping_address;

More about @javax.persistence.Column

@javax.persistence.Column(name = "MOTIVE_LABEL", nullable = false, unique = true) // With 'constraint MOTIVE_unique unique(MOTIVE_LABEL)'
private String _motive_label;


Other properties of @javax.persistence.Column:
  • insertable (default value is true)
  • updatable (default value is true)

Primary key

Simple primary keys are based on elementary types (long, Long, String…). The @javax.persistence.Id annotation is necessary:

@javax.persistence.Entity // Table name must be 'Customer'
public class Customer implements java.io.Serializable {
@javax.persistence.Id
@javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)'
private String _customer_PIN;

Composite primary key

Composite primary keys are based on non-elementary types that require the construction of devoted classes. The @javax.persistence.Embeddable and @javax.persistence.EmbeddedId annotations are necessary:

@javax.persistence.Embeddable
public class Criminal_casePK implements java.io.Serializable {
@javax.persistence.Basic(optional = false)
@javax.persistence.Column(name = "CRIMINAL_CASE_NUMBER")
private String _criminal_case_number;
@javax.persistence.Basic(optional = false)
@javax.persistence.Column(name = "JURISDICTION_NAME")
private String _jurisdiction_name;

@javax.persistence.Entity
@javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name
public class Criminal_case implements java.io.Serializable {
@javax.persistence.EmbeddedId // With 'constraint CRIMINAL_CASE_key primary key(CRIMINAL_CASE_NUMBER,JURISDICTION_NAME)'
private Criminal_casePK _criminal_casePK;

Alternative method:

public class Criminal_casePK implements java.io.Serializable { … // '@javax.persistence.Embeddable' is no longer used!

@javax.persistence.Entity
@javax.persistence.IdClass(Criminal_casePK.class)
@javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name
public class Criminal_case implements java.io.Serializable { …

Business versus generated primary key

Instead of having primary keys based on business fields, e.g., CUSTOMER_PIN above, primary keys may be generated by the DBMS (depending upon offered support for that). Strategies are: AUTO (default), IDENTITY, SEQUENCE and TABLE. Example:

@javax.persistence.Entity
public class Order implements java.io.Serializable {
@javax.persistence.Id
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
@javax.persistence.Column(name = "ORDER_ID") // With 'create table ORDER(ORDER_ID integer generated always as identity, …);'
private Integer _id;

Alternative example:

@javax.persistence.Id
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.SEQUENCE, generator = "MY_GENERATOR")
@javax.persistence.Column(name = "ORDER_ID") // With 'create sequence MY_GENERATOR;'
private Integer _id;

Entity Bean merging two or more tables

For instance, the CRIMINAL_CASE and JURISDICTION tables are merged into the Criminal_case Entity Bean:

@javax.persistence.Entity
@javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name
@javax.persistence.SecondaryTable(name = "JURISDICTION", pkJoinColumns = {@javax.persistence.PrimaryKeyJoinColumn(name = "JURISDICTION_NAME")})
public class Criminal_case implements java.io.Serializable { …


The pkJoinColumns attribute may be omitted here. The Criminal_case Entity Bean gets the _jurisdiction_address persistent field from JURISDICTION table:

@javax.persistence.Column(name = "JURISDICTION_ADDRESS", table = "JURISDICTION")
private String _jurisdiction_address;


Remarks:

Entity Bean relationships

The following JPA annotations are available to manage Entity Bean relationships (foreign keys in tables):
  • @javax.persistence.OneToOne
  • @javax.persistence.OneToMany
  • @javax.persistence.ManyToOne
  • @javax.persistence.ManyToMany
The following Java interfaces can be used to manage association ends with the many role:
  • java.util.Set<E>
  • java.util.List<E>
  • java.util.Map<K,V>

@javax.persistence.OneToOne

Case 1: the two related entities are linked by means of their primary keys

@javax.persistence.Entity // Table name must be 'Customer'
public class Customer implements java.io.Serializable {
@javax.persistence.Id
@javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)'
private String _customer_PIN;

@javax.persistence.OneToOne
@javax.persistence.PrimaryKeyJoinColumn
private Client _client; // Entity Bean 'Client' offers a primary key similar to '_customer_PIN' in 'Customer' Entity Bean

Case 2 (default mode): the two related entities are linked by means of a foreign key (this one is a priori unique in the target entity)

@javax.persistence.Entity
public class Order implements java.io.Serializable {
@javax.persistence.Id
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
@javax.persistence.Column(name = "ORDER_ID") // With 'create table ORDER(ORDER_ID integer generated always as identity, …);'
private Integer _id;

@javax.persistence.OneToOne // An order leads to one and only one invoice
@javax.persistence.JoinColumn(name = "ORDER_ID", referencedColumnName = "INVOICE_ID")
private Invoice _invoice;

Case 3: the two related entities are linked by means of a third-party table

This case is similar to @javax.persistence.ManyToOne (see below)

Bidirectionality

Entity Bean relationships can be either mono-directional or bidirectional. Example of bidirectionality with @javax.persistence.OneToOne:

@javax.persistence.Entity
public class Invoice implements java.io.Serializable {

@javax.persistence.OneToOne(mappedBy = "_invoice")
private Order _order; // Caution: JPA does not use this side to interact with the DBMS. Moreover, the mutual consistency has to be maintained by the developer

Note: the mappeBy annotation property is similar to the inverse = "true" indicator in Hibernate

@javax.persistence.OneToMany

See association from Prisoner to Conviction in figure below

@javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.REMOVE) // Cascade operations may be setup (no cascade by default) by means of javax.persistence.CascadeType
@javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER")
private java.util.Set<Conviction> _conviction;

@javax.persistence.ManyToOne

See association from Prisoner to Motive in figure below

@javax.persistence.ManyToOne(optional = false)
@javax.persistence.JoinColumn(name = "MOTIVE_NUMBER", referencedColumnName = "MOTIVE_NUMBER")
private Motive _incarceration_motive;

@javax.persistence.ManyToMany (using a third-party table: in boldface)

See association from Prisoner to Criminal_case (offense role in figure below)

@javax.persistence.ManyToMany(/* cascade = javax.persistence.CascadeType.MERGE */) // 'Prisoner' owns the relationship
@javax.persistence.JoinTable(name = "PRISONER_CRIMINAL_CASE", joinColumns = {
@javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER", referencedColumnName = "PRISON_FILE_NUMBER")},
// 'CRIMINAL_CASE_NUMBER'-'JURISDICTION_NAME' is a foreign key in 'PRISONER_CRIMINAL_CASE' to 'Criminal_case':
inverseJoinColumns = { @javax.persistence.JoinColumn(name = "CRIMINAL_CASE_NUMBER", referencedColumnName = "CRIMINAL_CASE_NUMBER"), @javax.persistence.JoinColumn(name = "JURISDICTION_NAME", referencedColumnName = "JURISDICTION_NAME") })
private java.util.Set<Criminal_case> _offense;

Bidirectionality

See association from Criminal_case to Prisoner (participant role in figure below)

@javax.persistence.ManyToMany(mappedBy = "_offense") // 'Criminal_case' does not own the relationship (cascading operations with 'javax.persistence.CascadeType' is a priori useless)
private java.util.Set<Prisoner> _participant; // Caution: JPA does not use this side to interact with the DBMS. Moreover, the mutual consistency has to be maintained by the developer

@javax.persistence.ManyToMany side loading

By default, multi-valued associations are ruled by the lazy loading mode (for performance reasons). One may change that as follows (see association from Prisoner to Shortened_sentence in figure below):

@javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.REMOVE, fetch = javax.persistence.FetchType.EAGER) // Each time, a 'Prisoner' Entity Bean is loaded (with 'find' for instance), all of its 'Shortened_sentence' Entity Beans are concomitantly loaded. Instead, the lazy mode leads to the loading of these when one accesses the collection itself using 'get_shortened_sentence'
@javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER")
private java.util.Set<Shortened_sentence> _shortened_sentence;
JPA Query Language (JPQL)

Principles

Basic requests

Advanced requests

Request

Prisoners "under remand", i.e., prisoners for which no conviction decision has been taken

SQL-like style

Native queries are standard SQL queries. They do not rely on Entity Beans

Declaration

@javax.persistence.NamedNativeQuery(name="Prisoner.Under_remand_SQL", query="SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)")

Usage

for (Object o : _entityManager.createNamedQuery("Prisoner.Under_remand_SQL").getResultList()) {
try {
Object[] prisoner_properties = (Object[]) o;
System.out.print("Under remand: - ");
for (int i = 0; i < prisoner_properties.length; i++) { System.out.print(prisoner_properties[i] + " - "); }
System.out.println();
}
catch (ClassCastException cce) { // the type of 'o' is not 'Object[]', so? }
}

JPQL style (♡) in line

Look at the Prisoner.Under_remand_JPQL named query

The power of JPQL relies on the strong utilization of navigations between Entity Beans

Collection-based requests

Request

Prisoners who are not involved in a given criminal case (the latter is a parameter in the named query, i.e., :criminal_case)

Declaration

@javax.persistence.NamedQuery(name = "Prisoner.Not_involved_in_criminal_case_V1", query = "SELECT p FROM Prisoner p WHERE :criminal_case NOT MEMBER OF p._offense"), // See offense navigation in figure above
@javax.persistence.NamedQuery(name = "Prisoner.Not_involved_in_criminal_case_V2", query = "SELECT p1 FROM Prisoner p1 WHERE p1 NOT IN (SELECT p2 FROM Criminal_case c INNER JOIN c._participant p2 WHERE c = :criminal_case)")/ / See participant navigation in figure above

Usage

public java.util.Collection<persistence.Prisoner> non_participants(persistence.Criminal_case criminal_case) {
assert (_entityManager != null);
criminal_case = _entityManager.find(persistence.Criminal_case.class, new persistence.Criminal_casePK(criminal_case.get_criminal_case_number(), criminal_case.get_jurisdiction_name()));
return _entityManager.createNamedQuery("Prisoner.Not_involved_in_criminal_case_V1").setParameter("criminal_case", criminal_case).getResultList();
}

Beyond SELECT

While DELETE and UPDATE JPQL are available, their possible usage is redundant with remove and merge from an entity manager. They may however be useful for bulk processing. Examples :
Inheritance

Overview

JPA enables the management of inheritance based on three strategies:
Inheritance in JPA is a support for polymorphic requests

SINGLE_TABLE strategy

Root class
@javax.persistence.Inheritance
@javax.persistence.DiscriminatorColumn(name = "SEX", discriminatorType = javax.persistence.DiscriminatorType.CHAR)
abstract public class Human_being implements java.io.Serializable { …
Descendant class
@javax.persistence.DiscriminatorValue('1')
public class Male extends Human_being { …

TABLE_PER_CLASS strategy

Root class
@javax.persistence.Inheritance(strategy = javax.persistence.InheritanceType.TABLE_PER_CLASS)
abstract public class Human_being implements java.io.Serializable { …
Descendant class
// No special annotation is required!
public class Male extends Human_being { …

JOINED strategy

Root class
@javax.persistence.Inheritance(strategy = javax.persistence.InheritanceType.JOINED)
@javax.persistence.DiscriminatorColumn(name = "DECISION_TYPE_NUMBER", discriminatorType = javax.persistence.DiscriminatorType.STRING)
abstract public class Judicial_decision implements java.io.Serializable { …
Descendant class
@javax.persistence.DiscriminatorValue(Conviction.DECISION_TYPE_NUMBER)
public class Conviction extends Judicial_decision {
public static final String DECISION_TYPE_NUMBER = "1";

Other useful annotations

@javax.persistence.MappedSuperclass: this annotation is used for factorizing JPA properties in a utility class but not for setting up inheritance from the database viewpoint (no concomitant use of @javax.persistence.Entity) is allowed! Example:

@javax.persistence.MappedSuperclass // No table is associated with this class. It just serves as factorization for inheriting classes
public class Customer implements java.io.Serializable {
@javax.persistence.Id
@javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)'
private String _customer_PIN;

@javax.persistence.OneToMany
private java.util.Collection<Order> _order;

Metadata