JPA 2.1 tutorial

In preparation for a timely release of Java EE 7 in April 2013, let's have a look at some interesting features of the JPA 2.1 specification.

JPA 2.1 was one of the first JSRs to be filed as part of Java EE 7. Several other specifications in Java EE 7 have released early drafts as well (JavaServer Faces 2.0, JAX-RS 2.0, CDI 1.1, more coming as well).Let's see some of the highlights that you are expected to find in JPA 2.1

Automatic schema generation

So far you have maybe used some provider specific features to generate the DB schema from the Java classes. For example Hibernate allows automatic schema creation using the following property:

 <properties>
            <property name="hbm2ddl.auto" value="create"/>
</properties>

The above strategy however lacks of some features (e.g. foreign key generation), is not portable thorugh other JPA providers and generally lacks of DB creation optimizations therefore it is applicable in some simple use cases, such as prototypes using simple DBs like HDB.

JPA 2.1 schema generation can be achieved both using a richer set of annotations and using some standard properties like in the following example:

<properties>
            <property name="javax.persistence.schema-generation-action" value="create"/>
            <property name="javax.persistence.schema-generation-target" value="database"/>            
</properties>

The two core properties which can control DB schema creation are:

javax.persistence.schema-generation-action Controls action to be taken by persistence provider "none", "create", "drop-and-create", "drop"
javax.persistence.schema-generation-target Controls whether schema to be created in database, whether DDL scripts are to be created, or both "database", "scripts", "database-and-scripts"

 Additional properties can be used to define target location of DDL scripts:   

javax.persistence.ddl-create-script-target Controls target locations for database create scripts java.io.Writer or URL strings
javax.persistence.ddl-drop-script-target Controls target locations for database drop scripts java.io.Writer or URL strings

Finally the following properties can be used to specify the source location of DDL scripts:   

javax.persistence.ddl-create-script-source Controls source locations for database create scripts java.io.Reader or URL strings
javax.persistence.ddl-drop-script-source Controls source locations for database drop scripts java.io.Reader or URL strings

  In order to achieve DB mapping of Java classes some existing standards will be used, that is:

  • Table name is defaulted from Entity name
  • Unidirectional OneToMany defaults to join table mapping

Additionally some new annotations are added, such as the @Index annotation which can be used to specify additional indexes and the order of Indexes:

@Table(indexes={@Index(columnList="NAME")
                              @Index(columnList="CUSTOMER_ID")})
@Entity public class Customer {
@Id private Integer id;
private String name;
...
@ManyToOne
private Country country;
...
}

Another annotation which can be used is @ForeignKey which specifies foreign key constraint. Be careful as this annotation overrides the persistence provider’s default foreign key treatment !)

@Entity public class Customer {

 

@Id private Integer id;
private String name;

@JoinColumn(foreignKey=@ForeignKey(foreignKeyDefinition="FOREIGN KEY (COUNTRY_ID) REFERENCES COUNTRY")) 
private Country country;

. . .

}

Unsynchronized persistence context

In JPA, by default the persistence context is synchronized with the underlying resource manager. This means that any updates made to the persistence context are propagated to the resource manager. JPA 2 introduces the Unsynchronized persistence context which allows an application to control the binding of the CMP context to the current transaction. So, besides the default SYNCHRONIZED enum type, there is now an additional type named UNSYNCHRONIZED as shown in the following example.

Basically an UNSYNCHRONIZED persistence context works by propagating the context within the jta transaction but not flushing the changes to the database, until the joinTransaction is invoked:

@Stateful
public class ShoppingCart {


@PersistenceContext(type=EXTENDED,synchronization=UNSYNCHRONIZED)
EntityManager em;

Customer customer;
Order order;

public void startToShop(Integer custId) {
  customer = em.find(Customer.class,custId);
  order = new Order(); 
}

public void addToCart(Book book) {
  Item item = new Item(book);
  order.addItem(item); 
}
public void confirmOrder() {
  em.joinTransaction();
  customer.addOrder(order);
}
}

UNSYNCHRONIZED persistence context allows modeling JPA conversations: that is tracking persistent changes, but commit them only at end of conversation, not each transaction

Stored procedure mapping

Up to now you used to hack stored procedure invocations in Hibernate using several strategies, such as using native SQL

Query query = session.createSQLQuery(
    "CALL GetStocks(:stockCode)")
    .addEntity(Stock.class)
    .setParameter("stockCode", "7277");
    
Now there's a portable way to achieve it using:


StoredProcedureQuery spq = em.createStoredProcedureQuery("PERSON_SP");

   
If we have any parameters in this stored procedure we need to register them, for example:
spq.registerStoredProcedureParameter(1, String.class, ParameterMode.INOUT);
spq.setParameter(1, "FRANK");
spq.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN);
spq.setParameter(2, 100);

You can define it as well using the @NamedStoredProcedureQuery:
@Entity
@NamedStoredProcedureQuery(name="PERSON_StoredProcedure", procedureName="PERSON_SP")
public class Product {
 . . .
}

and in your JPA client:
StoredProcedreQuery spq = EntityManager.createNamedStoredProcedureQuery("PERSON_StoredProcedure");
spq.registerStoredProcedureParameter(1, String.class, ParameterMode.INOUT);
spq.setParameter(1, "FRANK");
spq.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN);
spq.setParameter(2, 100);
 
query.execute();
String response = query.getOutputParameterValue(1);

 

Follow us on Twitter