The Spring JPA specification, available in the org.springframework.orm.jpa
package, provides comprehensive support Java Persistence API is similar to integration with Hibernate, while allowing for a base implementation to provide additional functionality.
Three options for configuring JPA in a Spring environment
Spring's JPA support provides three ways to configure the EntityManagerFactory
from JPA, which is used by the application to obtain the entity manager.
Using
LocalEntityManagerFactoryBean
Getting
EntityManagerFactory
fromJNDI
Using
LocalContainerEntityManagerFactoryBean
Using LocalEntityManagerFactoryBean
This option can only be used in simple deployment environments such as standalone applications and integration tests.
LocalEntityManagerFactoryBean
creates an EntityManagerFactory
suitable for simple deployment environments where the application uses only JPA to access data . The bean factory uses a mechanism to automatically determine the PersistenceProvider
from JPA (as per JPA bootstrapping in Java SE) and in most cases requires only the name of the persistence unit to be specified. In the following XML example, the following bean is configured:
<beans>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myPersistenceUnit"/>
</bean>
</beans>
This form of JPA deployment is the simplest and most limited. You cannot reference an existing DataSource
bean definition from JDBC, and there is no support for global transactions. Additionally, the binding (bytecode conversion) of persistent classes is vendor-specific, and it is often necessary to specify a specific JVM agent at startup. This option will only be sufficient for standalone applications and test environments for which the JPA specification is designed.
Getting EntityManagerFactory from JNDI
This option can be used when deploying to a Java EE server. Check the documentation for your server to learn how to deploy a custom JPA provider on your server, allowing you to use a provider other than the server's default provider.
Getting EntityManagerFactory
from JNDI (for example , in the Java EE environment) is a matter of changing the XML configuration, as shown in the following example:
<beans>
<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>
This action assumes standard Java EE bootstrap. The Java EE server automatically detects persistence units (essentially META-INF/persistence.xml
files in application jar files) and persistence-unit-ref
entries in the Java deployment descriptor EE (for example, web.xml
) and defines the location of the environment naming context for these persistence units.
In such a scenario, deployment of persistence units, including binding (bytecode transformation) of persistent classes storage is entirely the responsibility of the Java EE server. The DataSource
from JDBC is defined through the JNDI location in the META-INF/persistence.xml
file. EntityManager
transactions are an integral part of the server's JTA subsystem. Spring simply uses the resulting EntityManagerFactory
, passing it to application objects via dependency injection and managing transactions for the persistence unit (typically via a JtaTransactionManager
).
If in a single application multiple persistence units are used, the bean names of those persistence units retrieved from JNDI must match the names of the persistence units that the application uses to refer to them (for example, in the @PersistenceUnit
and @PersistenceContext
annotations).
Using LocalContainerEntityManagerFactoryBean
This option can be used to fully utilize JPA facilities in a Spring-based application environment. This includes web containers such as Tomcat, standalone applications, and integration tests with complex persistence requirements.
LocalSessionFactoryBean
from Hibernate instead of the regular
LocalContainerEntityManagerFactoryBean
from JPA, allowing it to interact with the JPA access code as well as the native Hibernate access code. For details, see
"Native Hibernate setup for interoperability with JPA".
LocalContainerEntityManagerFactoryBean
gives full control over the EntityManagerFactory
configuration and is suitable for environments where fine-tuning is required. LocalContainerEntityManagerFactoryBean
creates an instance of PersistenceUnitInfo
based on the persistence.xml
file provided by the dataSourceLookup
strategy and specified by loadTimeWeaver
. This way, you can work with custom data sources outside of JNDI and manage the binding process. The following example shows a typical bean definition for a LocalContainerEntityManagerFactoryBean
:
<beans>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="someDataSource"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
</beans>
The following example shows a typical persistence.xml
file:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<mapping-file>META-INF/orm.xml</mapping-file>
<exclude-unlisted-classes/>
</persistence-unit>
</persistence>
<exclude-unlisted-classes/> ;
indicates that annotated entity classes should not be scanned. An explicit value of "true" (
<exclude-unlisted-classes>true</exclude-unlisted-classes/>
) also means no check.
<exclude-unlisted-classes>false</exclude-unlisted-classes/>
causes a check. However, we recommend omitting the
exclude-unlisted-classes
element if you want to scan entity classes.
Using the LocalContainerEntityManagerFactoryBean
is the most efficient JPA configuration option, providing flexible local configuration in the application. It supports references to existing DataSource
from JDBC, supports local and global transactions, and so on. However, it also imposes requirements on the runtime environment, such as having a bindable class loader if the persistence provider requires bytecode conversion.
This option may conflict with the Java EE server's native JPA facilities. In a full Java EE environment, consider getting EntityManagerFactory
from JNDI. Alternatively, define a custom persistenceXmlLocation
in the LocalContainerEntityManagerFactoryBean
definition (for example, META-INF/my-persistence.xml) and only include a handle with that name in your application's jar files. Since the Java EE server only looks for standard META-INF/persistence.xml
files, it ignores such custom persistence units, hence avoiding conflicts with Spring-based JPA configuration. (This applies, for example, to Resin 3.1).
The LoadTimeWeaver
interface is a class contained in Spring that allows you to connect ClassTransformer
instances from JPA in a specific way, depending on the whether the environment is a web container or an application server. Connecting ClassTransformers
via agent is usually ineffective. Agents run throughout the virtual machine and check every class that is loaded, which is usually undesirable in a production server environment.
Spring contains several implementations of LoadTimeWeaver
for different environments, allowing instances of to be used ClassTransformer
is only per class loader, not per virtual machine.
More information about LoadTimeWeaver
implementations and their configuration, both typed and adapted to different platforms (such as Tomcat, JBoss and WebSphere), see the section on configuration Spring in the AOP chapter.
As described in the section on Spring configuration, you can configure LoadTimeWeaver
for the entire context using the @EnableLoadTimeWeaving
annotation or the context:load-time- XML element weaver
. This global binding tool is automatically picked up by all LocalContainerEntityManagerFactoryBean
instances from JPA. The following example shows the preferred way to configure the binder at boot time to automatically detect the platform (such as Tomcat's binder-enabled class loader or Spring's JVM agent) and automatically propagate the binder to all beans that support the binder:
<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
However, if necessary, you can manually set the dedicated binding tool through the loadTimeWeaver
property, as shown in following example:
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</property>
</bean>
Regardless of how load-time (LTW) binding is configured, with this technique JPA applications that rely on instrumentation can run on the target platform (eg Tomcat) without the need for an agent. This is especially important if host applications use different JPA implementations, since JPA resolvers are applied only at the loader class level and are thus isolated from each other.
Working with multiple persistence units
For applications that use multiple persistence unit locations (stored, for example, in different JAR files on the classpath), Spring offers a PersistenceUnitManager
that acts as a central repository and avoids the persistence unit discovery process, which can be costly. The default implementation allows multiple locations to be specified. These locations are parsed and subsequently retrieved via the persistence unit name. (By default, the classpath searches for META-INF/persistence.xml
files). The following example has multiple locations configured:
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
<value>classpath:/my/package/**/custom-persistence.xml</value>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key="localDataSource" value-ref="local-db"/>
<entry key="remoteDataSource" value-ref="remote-db"/>
</map>
</property>
<!-- if the data source is not specified, use this -->
<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="pum"/>
<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>
The default implementation allows PersistenceUnitInfo
instances to be configured (before they are passed to the JPA provider) or declaratively (via its properties that affect all hosted units) or programmatically (via PersistenceUnitPostProcessor
, which allows sampling of persistence units). If PersistenceUnitManager
is not set, then it will be created and used inside the LocalContainerEntityManagerFactoryBean
.
Background bootstrap
LocalContainerEntityManagerFactoryBean
supports background bootstrap functionality via the bootstrapExecutor
property, as shown in the following example:
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="bootstrapExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</property>
</bean>
The actual JPA provider bootstrap is passed to the specified worker and then, in parallel, to the application bootstrap thread. The EntityManagerFactory
public proxy can be injected into other application components and is even capable of responding to EntityManagerFactoryInfo
configuration checks. However, if the actual JPA provider is accessed by other components (for example, by calling createEntityManager
), those calls block until the background bootstrap is complete. In particular, if you are using Spring Data JPA, be sure to configure lazy bootstrapping for its repositories as well.
JPA-based DAO implementation: EntityManagerFactory
and EntityManager
EntityManagerFactory
instances are thread-safe,
EntityManager
instances are not. An embedded
EntityManager
from JPA behaves like an
EntityManager
derived from the application server's JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional
EntityManager
, if there is one. Otherwise, it falls back to a newly created
EntityManager
for each operation, effectively making its use thread safe.
It is possible to write code in plain JPA without any Spring dependencies using the injected EntityManagerFactory
or EntityManager
. Spring can recognize @PersistenceUnit
and @PersistenceContext
annotations at both the field and method level if PersistenceAnnotationBeanPostProcessor
is enabled. The following example shows a typical JPA DAO implementation using the @PersistenceUnit
annotation:
public class ProductDaoImpl implements ProductDao {
private EntityManagerFactory emf;
@PersistenceUnit
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
public Collection loadProductsByCategory(String category) {
EntityManager em = this.emf.createEntityManager();
try {
Query query = em.createQuery("from Product as p where p.category = ?1");
query.setParameter(1, category);
return query.getResultList();
}
finally {
if (em != null) {
em.close();
}
}
}
}
class ProductDaoImpl : ProductDao {
private lateinit var emf: EntityManagerFactory
@PersistenceUnit
fun setEntityManagerFactory(emf: EntityManagerFactory) {
this.emf = emf
}
fun loadProductsByCategory(category: String): Collection<*> {
val em = this.emf.createEntityManager()
val query = em.createQuery("from Product as p where p.category = ?1");
query.setParameter(1, category);
return query.resultList;
}
}
The predecessor DAO is independent of Spring and still fits well within the Spring application context. Moreover, the DAO takes advantage of annotations to request the implementation of a standard EntityManagerFactory
, as shown in the following example bean definition:
<beans>
<!-- bean postprocessor for JPA annotations -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
As an alternative to explicitly defining PersistenceAnnotationBeanPostProcessor
, consider using the context:annotation-config
XML element from Spring in the application context configuration. This way, all the standard Spring post processors for annotation-based configuration, including CommonAnnotationBeanPostProcessor
and so on, will be automatically registered.
Consider the following example:
<beans>
<!-- postprocessors for all standard configuration annotations -->
<context:annotation-config/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
The main problem with such a DAO is that it always creates a new EntityManager
through a factory. You can avoid this by requesting a transactional EntityManager
(also called a "generic EntityManager" because it is a generic, thread-safe proxy for the actual transactional EntityManager) to be injected instead of the factory. The following example shows how to do this:
public class ProductDaoImpl implements ProductDao {
@PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
}
class ProductDaoImpl : ProductDao {
@PersistenceContext
private lateinit var em: EntityManager
fun loadProductsByCategory(category: String): Collection<*> {
val query = em.createQuery("from Product as p where p.category = :category")
query.setParameter("category", category)
return query.resultList
}
}
The @PersistenceContext
annotation has an optional type
attribute, which defaults to PersistenceContextType.TRANSACTION
. You can use this default value to obtain a shared EntityManager
proxy. The alternative, namely PersistenceContextType.EXTENDED
, is a completely different matter. The result is a so-called extended EntityManager
, which is not thread-safe and therefore should not be used in a bean that is exposed to concurrent access, such as a Spring managed singleton bean. Instances of the extended EntityManager
are intended to be used exclusively by stateful beans, such as those contained in a session, and the lifecycle of the EntityManager
is not tied to the current transaction, but is entirely dependent on applications.
The injected EntityManager
is managed by Spring (takes into account the current transaction). Even if the new DAO implementation uses EntityManager
method-level injection instead of EntityManagerFactory
, no changes to the application context XML are required due to the use of annotations.
The main advantage of this is DAO style is that it only depends on the Java Persistence API. There is no need to import any Spring class. Moreover, since JPA annotations are recognized, the injection is applied automatically by the Spring container. This is attractive from a non-invasive perspective and may feel more natural to JPA developers.
JPA transactions managed by Spring
The recommended strategy for JPA is local transactions using JPA's built-in transaction support. Spring's JpaTransactionManager
offers many of the features familiar from JDBC local transactions (such as transaction-specific isolation levels and resource-level read-only optimizations) over any regular JDBC connection pool (without XA requirements).
JPA via Spring also allows a configured JpaTransactionManager
to open a JPA transaction for a JDBC access code that accesses the same DataSource
, provided that the registered JpaDialect
supports retrieving the underlying Connection
from JDBC. Spring contains dialects for implementations of EclipseLink and Hibernate via JPA.
HibernateTransactionManager
is capable of interacting with JPA access code, adapting to some of the features of Hibernate and providing interoperability with JDBC. This makes special sense in combination with the
LocalSessionFactoryBean
setting. For more information, see
"Native Hibernate setup for interoperability with JPA".
Introduction to JpaDialect
and JpaVendorAdapter
As an extended feature of JpaTransactionManager
and subclasses of AbstractEntityManagerFactoryBean
allow you to pass a custom JpaDialect
to the jpaDialect
bean property. A JpaDialect
implementation may include the following advanced features supported by Spring, usually depending on the vendor:
Use specific transaction semantics (for example, custom isolation level or timeout transactions)
Get a JDBC transactional
Connection
(to open it to JDBC-based DAOs)Advanced conversion of
PersistenceExceptions
toDataAccessExceptions
from Spring
This is especially useful in the case of special transaction semantics and for advanced exception transformations. The default implementation of (DefaultJpaDialect
) does not provide any special functionality, and if the previously listed functionality is required, the appropriate dialect must be specified.
JpaVendorAdapter
, an even broader provider adaptation tool primarily for fully customizing Spring's
LocalContainerEntityManagerFactoryBean
, combines the capabilities of
JpaDialect
with other vendor-specific options default. Setting
HibernateJpaVendorAdapter
or
EclipseLinkJpaVendorAdapter
is the most convenient way to automatically configure
EntityManagerFactory
for Hibernate or EclipseLink, respectively. Please note that these provider adapters are primarily intended for use with Spring-based transaction management (that is, for use with
JpaTransactionManager
).
See: javadoc by JpaDialect
and JpaVendorAdapter
for more information on how they work and how they are used within the Spring JPA support.
Configuring JPA with JTA Transaction Management
As an alternative to JpaTransactionManager
, Spring also allows you to coordinate transactions with multiple resources via JTA, either in a Java EE environment or using a separate transaction coordinator, such as Atomikos. In addition to choosing JtaTransactionManager
instead of JpaTransactionManager
, there are a few more steps you need to take:
The underlying JDBC connection pools must be XA compatible and integrated with your transaction coordinator. Typically in a Java EE environment this is done simply by opening a
DataSource
of a different type via JNDI. See your application server documentation for details. Likewise, a standalone transaction coordinator typically comes with specializedDataSource
options integrated with XA. Again, check the documentation.The
EntityManagerFactory
setting from JPA must be configured for JTA. It all depends on the manufacturer, but usually this is done through special properties, which should be set asjpaProperties
for theLocalContainerEntityManagerFactoryBean
. In the case of Hibernate, these properties are even version dependent. See the Hibernate documentation for details.HibernateJpaVendorAdapter
from Spring applies certain Spring-specific defaults, such as connection release mode,on-close
, which is the same as Hibernate's own default in Hibernate 5.0, but is no longer the same in Hibernate 5.1+. To configure JTA, ensure that your persistence unit's transaction type is declared as "JTA". Alternatively, set thehibernate.connection.handling_mode
property from Hibernate 5.2 toDELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
to restore Hibernate's own default value. For related notes, see "False application server warnings when using Hibernate ".Alternatively, consider getting the
EntityManagerFactory
from the application server itself (that is, via a JNDI lookup instead of a locally declaredLocalContainerEntityManagerFactoryBean
). The server-providedEntityManagerFactory
may require special definitions in your server configuration (making deployment less platform independent), but is tuned for the server's JTA environment.
Native Hibernate configuration and native Hibernate transactions for interoperability with JPA
Native LocalSessionFactoryBean
configuration combined with HibernateTransactionManager
allows interoperability with @PersistenceContext
annotations and other JPA access code. Hibernate's SessionFactory
now natively implements JPA's EntityManagerFactory
interface, and Hibernate's Session
handle is now JPA's EntityManager
natively. Spring's JPA support automatically defines native Hibernate sessions.
This native Hibernate setup can therefore serve as a replacement for the standard LocalContainerEntityManagerFactoryBean
and JpaTransactionManager
combination from JPA in many scenarios , allowing you to interact with SessionFactory.getCurrentSession()
(as well as HibernateTemplate
) along with the @PersistenceContext EntityManager
annotation within a single local transaction. This setup also allows for tighter integration with Hibernate and greater configuration flexibility since it is not limited by JPA bootstrap template contracts.
In this case, HibernateJpaVendorAdapter
configuration is not needed because Spring has built-in configuration Hibernate provides even more functionality (such as custom Hibernate Integrator configuration, Hibernate 5.3 bean container integration, and stronger optimizations for read-only transactions). Last but not least, you can also express native Hibernate configuration via LocalSessionFactoryBuilder
, easily iterating the configuration based on the @Bean
annotation (without using FactoryBean
).
LocalSessionFactoryBean
and LocalSessionFactoryBuilder
support background bootstrapping, like LocalContainerEntityManagerFactoryBean
from JPA. For introductory information, see "Background bootstrap".
For a LocalSessionFactoryBean
this is available through the bootstrapExecutor
property. In a software LocalSessionFactoryBuilder
the overloaded buildSessionFactory
method takes an executor argument initial loading.
GO TO FULL VERSION