When comes to ORM frameworks, plenty of frameworks exist. We have already seen Hibernate in our last chapter. Frameworks may have a free hand when it comes to implementation if no standard is around. A standard or a specification helps the end user in swapping the frameworks without much hassle should the need arise. Java folks realised the need of a persistence standard that would help the user community. The standard is called a Java Persistence API (JPA)—an API that helps to standardize the Java Persistence world.
In this chapter, we will look at the Java Persistence API at a high level and at Spring’s support to use the API with few providers, especially with the Hibernate provider. As expected, there will be a few players who implement the specification and bring the standard to life. We see discuss one such provider—Hibernate itself—in this chapter.
The JPA defines an EntityManager
interface, which is
basically the heart of the API. It is similar to Hibernate’s Session
, forming the core of the application to perform database
operations.
As you create Session
from a SessionFactory
, it’s not hard to understand that you use EntityManagerFactory
to create an instance of EntityManager
. However, because JPA is a standard applicable to Enterprise and
Standalone applications, there are a couple of modes for obtaining or creating the EntityManagerFactory
itself—one that will be created in a
managed environment such as Application Servers or Web containers while the other in a
standalone application.
Once you have the EntityManager
(obtained from EntityManagerFactory
), the next step is to declare a
persistence unit. A persistence unit is a logical group of persistent
classes (called entities in JPA lingo), database settings, and relational mappings.
We will see the EntityManager
and its factory in action
in a few pages, but for now, let’s look at the following snippet that indicates a persistence-unit
:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="trade-mysql-pu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>com.madhusudhan.jsd.domain.jpa.Trade</class> <properties> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/JSDATA"/> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> ... </properties> </persistence-unit> </persistence>
As you can see, a persistent-unit
named trade-mysql-pu
was created with a single persistent entity
(Trade
) and the HibernatePersistence
as the provider (the implementor of the JPA Specification).
The properties indicate the settings of the database which are similar to the DataSource
definition properties.
One norm you should follow is to create the persistence.xml
file under a folder named META-INF.
The providers are required to look for this file under that folder. If
the folder doesn’t exist, create one and add it to the classpath.
The class attribute defines the persistent entity as seen in the
above XML file. We create an entity with appropriate annotations (@Entity
, @Column
, @Id
, and so on).
See below for an example of how the Trade
entity is defined:
@Entity
@Table(name="TRADES")
public class Trade {
@Column( nullable=false)
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id = 0;
@Column
private String direction = null;
@Column
private String account = null;
...
The entity annotation describes that this POJO is a persistable entity (a domain object)
which maps to the TRADES
table. You do not have to provide
the table details if the class name matches to the table name (in our case, the domain object
is Trade
which doesn’t match to table TRADES
). The properties follow the same path—they match to the
column names.
The last thing to understand, which is covered in the next few pages, is how EntityManagerFactory
’s and EntityManager
’s are created.
The JPA specification classifies two types of entity managers: one that runs in a container-managed environment, and another that runs in a standalone JVM. The former one is typically a Java Enterprise Edition (JEE) container such as an application server or a web container, while the latter is a Java Standard Edition standalone program.
The EntityManager
itself is no different in both types
but the EntityManagerFactory
that creates the EntityManager
is a bit unique in how it is configured and
created.
In a standalone environment, you should create the EntityManager
as shown here:
private EntityManagerFactory factory = null;
private EntityManager entityManager = null;
..
private void init() {
factory = Persistence.createEntityManagerFactory("trade-mysql-pu");
entityManager = factory.createEntityManager();
}
You should pass in the name of the previously defined persistence
unit (from persistence.xml
) to the
createEntityManagerFactory()
method. We
then obtain the EntityManager
by
calling createEntityManager
on the
factory.
In a container-managed environment, the class with a reference to the entity manager
(typically DAO objects) will be injected with an existing EntityManager
. The responsibility of looking up the persistence unit, creating
the factory, and subsequently creating and injecting the EntityManager
are all taken care of by the JEE application container.
Note that, however you get the EntityManager
, whether
from a JEE container or in a standalone mode, the operations on it are always the same. The
fundamental difference involves its creation—not its workings.
What’s the value input from Spring in supporting JPA, you might ask?
The Spring framework supports the JPA API in couple of ways, very similar to support for
Hibernate. One way is by providing the classic template: a JpaTemplate
class. This class is basically a wrapper around the EntityManager
similar to other templates such as HibernateTemplate
.
The second way is by allowing the developer to use plain JPA API in the applications via
an injected EntityManager
class. If you are confused as to
what approach to take, go with using plain API if possible. This way, Spring will be used
solely for dependency injection thus avoiding any dependencies on its framework classes.
Should you have earlier versions (before 3.x), perhaps sticking to template style might be
easier.
Let’s explore both of these use cases in detail.
Basically, Spring encapsulates the EntityManagerFactory
in its own FactoryBean
implementation and injects them into
the applications where it is needed.
Spring uses two implementations of FactoryBean
for
providing the EntityManager
s in respective
environments:
org.springframework.orm.jpa.LocalEntityManagerFactoryBean
This
FactoryBean
creates theEntityManagerFactory
for standalone environments. This implementation provides a simplefactory
that has limitations. It cannot participate in globaltransaction
s, cannot work withDataSources
.org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
This factory bean provides the
EntityManagerFactory
for enterprise environments. Note how its classname has the word “Container” embedded in it, compared to the previousLocalEntityManagerFactoryBean
class.
We will see both of them in action in the next section.
In order to provide the EntityManager
to your
standalone Spring application, what we need to do is to define the LocalEntityManagerFactoryBean
in your configuration file, as shown in the
following snippet:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="trade-mysql-pu" /> </bean>
Note that the persistenceUnitName
refers to the
persitence-unit
name provided in the persistence.xml
file. The bean is now configured and ready to be
injected. The following snippet shows how it has been injected into our TradeDAO
object:
<bean id="entityManagerFactory" .. <bean id="tradeDAO" class="com.madhusudhan.jsd.jpa.TradeDAO"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
As expected, the factory will be injected into TradeDAO
and it’s the TradeDAO
’s job to create the EntityManager
from the factory. This is shown
in the following snippet:
private EntityManagerFactory entityManagerFactory = null; private EntityManager manager = null; public TradeDAO() { manager = getEntityManagerFactory().createEntityManager(); } //setters for EntityManagerFactory - will be injected by Spring public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; } public EntityManagerFactory getEntityManagerFactory() { return entityManagerFactory; }
Now that we have created the EntityManager
instance,
our job is done. We can use its contract API to execute data access operations such as
creating, finding, and deleting entities, as well as many more operations against a
database.
I’ve created few methods on the TradeDAO
shown below:
public class TradeDAO { private EntityManagerFactory entityManagerFactory = null; private EntityManager manager = null; void persist(Trade t){ // persist the object getManager().persist(t); } public void delete(Trade t){ // delete the row getManager().remove(t); } ... }
In order to insert a Trade
object, we use the
persist()
method exposed on the EntityManager
. Obviously, we need to start a transaction
before
we execute any data access operation and commit the transaction
. Similarly, there are a few
other methods such as merge, remove, and find to do relevant operations. Please refer to the
standard API documentation for more details on using these methods beyond the examples shown
here.
It is time to see how Spring provides a managed entity factory. In this situation,
Spring acts as a container itself and all configuration is managed in its context file. As
we learned earlier, the EntityManagerFactory
is
encapsulated by LocalContainerEntity
ManagerFactoryBean
,
which is recommended for most of the applications, including those meant to be used as standalone programs. This factory
provides support for global and local transaction
s while
utilizing the existing DataSource
definitions.
Let’s see how we create the EntityManagerFactory
via the Spring
container.
The following snippet shows the configuration required for creating the factory:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="mySqlDataSource" /> <property name="packagesToScan" value="com.madhusudhan.jsd.jpa" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> <property name="generateDdl" value="true" /> <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> </bean> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource"> ... </bean>
There are few interesting properties that deserve mentioning:
The dataSource
property refers to the standard JDBC DataSource
that is configured in the same XML file as we did before (shown as
Apache Common’s DBCP DataSource in the snippet).
The factory class points to the framework’s
LocalContainerEntityManagerFactoryBean
class.The
pacakagesToScan
attribute instructs the framework to browse through the relevant package (com.madhusudhan.jsd.jpa
in this case) to find the persistent entities by looking at the@Entity
annotations on the class.The
jpaVendorAdapter
attributes tells the bean to use Hibernate’s persistence provider. You may provide additional properties to the adapter such asgenerateDdl
,databasePlatform
(Dialect),batchSize
, and so on.
Now that all the moving pieces are, or have been assembled, invoke the data access
methods on TradeDAO
. Because of all the changes we made
previously were config related, there wouldn’t be any changes to the DAO object. Hence you
can re-use the same TradeDAO
:
public class TradeDAO { ... public void persist(Trade t){ // persist the object getManager().persist(t); } public void delete(Trade t){ // delete the row getManager().remove(t); } ... }
Use the DAO to execute relevant data access functions. Inserting a new Trade
would be extraordinarily simple, as demonstrated
here:
public class TradePersistorTest {
...
public TradePersistorTest() {
ctx = new ClassPathXmlApplicationContext("jpa-beans.xml");
dao = ctx.getBean("tradeDao",TradeDAO.class);
}
public void persist(Trade p){
dao.persist(p);
}
public static void main(String[] args) {
TradePersistorTest test = new TradePersistorTest();
Trade t = new Trade();
//..set values on Trade t
test.persist(t);
}
}
As you can see, once you get the DAO bean from the container, invoke the persist
operation to store a new Trade
.
The above methods must be executed in a transaction
. If you are using programmatic
demarcation of transaction
s, perhaps each of your data access operation should begin with a
new transaction
and end the transaction when done. Of course, you can span your transaction
across multiple operations.
The EntityManager
exposes methods to begin, commit,
and/or rollback transaction
s. For example, the following snippet shows utility methods that
create a new transaction
and commit an existing transaction
:
//beginning your transaction private void begin() { getManager().getTransaction().begin(); } //committing your transaction private void commit() { getManager().getTransaction().commit(); }
In our DAO, we should demarcate the transactional
boundaries as
shown below:
public void persist(Trade p){
// begin your tx
begin(); //calls the above begin method
// do your job
dao.persist(p);
// end your transaction
commit();// calls the above commit method
}
Spring also provides declarative transactional support. Please refer to section on
declarative transaction
s discussed in
Chapter 3.
While we can mix and match the framework’s elements into our data access layer, the recommended approach is to use the plain JPA API to execute data access operations. Spring’s support is excellent in achieving this goal, as we will see in few minutes.
The DAO’s setEntityManagerFactory
method should be
annotated with @PersistenceUnit
annotation. Spring understands this annotation and accordingly will
inject EntityManagerFactory
into the
DAO.
See the reworked example
DAO using @PersistenceUnit
annotation:
public class TradeDAO { @PersistenceUnit public void setEntityManagerFactory (EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; } ... }
Did you notice that there are no Spring classes in the above DAO? The @Persistence
Unit
annotation belongs to the JPA specification, which makes
our DAO fully JPA-compliant. However, how does Spring know that it has to inject an EntityManagerFactory
when the method is annotated with @PersistenceUnit
annotation?
Well, it turns out that the magic is performed by Spring’s post
processor bean: Persistence
AnnotationBeanPostProcessor
. This
bean is wired into your configuration XML, as shown below:
<!-- Reads the annotations --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <bean id="tradeDao" class="com.madhusudhan.jpa.plain.TradeDAO"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="trade-mysql-pu" /> </bean>
The rest of the beans in the XML configuration file are self-explanatory. If you wish to eliminate declaring individual post processors as shown above, you can use the following snippet that scans all of the post processors:
<context:annotation-config/>
Now that you have all the ammunition you need, all you have to do is to execute the functionality on the DAO via your test classes.
public class TradePersistorPlainJpaTest { public TradePersistorPlainJpaTest() { ctx = new ClassPathXmlApplicationContext("jpa-plain-beans.xml"); dao = ctx.getBean("tradeDao",TradeDAO.class); } public void persist(Trade p){ dao.persist(p); } ... }
That’s about it!
We explore the Spring’s template support in the next section.
The JpaTemplate
follows the same template pattern
that we have observed all along in the Spring’s framework. It encapsulates the nitty-gritty
of EntityManager
and EntityManagerFactory
implementations.
Note
The JpaTemplate
has been deprecated since Spring version 3.1.x. It is strongly advised to use
JPA API rather than JpaTemplate
if
you are using or migrating to version 3.1.x.
Define a bean named jpaTemplate
and wire it with an EntityManagerFactory
. This is shown
below:
<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
Note that the entityManagerFactory
is created from
the pre-defined persistence-unit
(unlike ContainerManagerFactory
where the persistence unit definition is
not required).
You do not need to change your definition of DAO.
Both are shown in the following snippet:
<!-- Using JPATemplate --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="trade-mysql-pu" /> </bean> <bean id="tradeDao" class="com.madhusudhan.jpa.TradeDAO"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="jpaTemplate".../>
The TradeDAO
is :
public class TradeDAO { private JpaTemplate jpaTemplate = null; public void persist(Trade t){ getJpaTemplate().persist(t); } //setter and getter for jpaTemplate ... }
Now that you have the DAO, fetch it via your application context and invoke the appropriate methods.
public class TradePersistorJpaTemplateTest { public TradePersistorJpaTemplateTest() { ctx = new ClassPathXmlApplicationContext("jpa-beans.xml"); dao = ctx.getBean("tradeDao",TradeDAO.class); } public void persist(Trade p){ dao.persist(p); } ... }
Note that JpaTemplate
introduces another layer on top
of your DAO layer, which is not really necessary.
As usual, Spring provides its XXXSupport classes for our convenience.
All you have to do is to let your DAO class extend the framework’s JpaDaoSupport
class. It then will have a reference to JpaTemplate
.
The DAO class should look like this:
public class JPAPriceDAOSupport extends JpaDaoSupport { public void persist(Trade t) { getJpaTemplate().persist(t); } }
Because you have extended the JpaDaoSupport
class, the JpaTemplate
will be readily available to your
DAO instance. As you can see, the getJpaTemplate()
will return the template object
which is then used to invoke the appropriate data access
operations.
The wiring of the DAO bean is shown below, which gets a EntityManagerFactory
instance:
<bean id="jpaPriceDAOSupport" class="com.madhusudhan.jsd.jpa.support.JPAPriceDAOSupport"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="TradePU" /> </bean>
Internally, the support class relies on JpaTemplate
to
do the actual work.
Note that the JpaDaoSupport
class is deprecated in
Spring version 3.1 or later. This way, Spring folks strongly encourage you to move on to using
Spring with plain JPA API.
In this chapter, we looked at the Java Persistence API (JPA) from a very high level. We
then tried to understand the Spring’s support in bringing the JPA into our Java application
world. We learned about the EntityManagerFactory
and
EntityManager
which form the basis to understanding the
JPA solutions. We also looked at standalone versus managed environments, and ways to create
the factories and instantiate the EntityManager
s in these
environments. We created our examples using plain JPA API and framework-dependent templates
and support classes.
Get Just Spring Data Access now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.