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 from JNDI

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

If you need to specifically configure your Hibernate setup, then An alternative would be to configure a native 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>
Abbreviation <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).

When anchoring is necessary during loading?

Not all JPA providers require a JVM agent. Hibernate is just such an example. If your vendor does not require an agent, or you have other alternatives, such as the ability to apply enhancements at build time via a custom compiler or Ant task, then you should not use the load-time binding tool.

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

Although 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:

Java

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

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:

Java

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

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.

Method and field level dependency injection

You can apply dependency injection annotations (such as @PersistenceUnit and @PersistenceContext) to fields or methods within a class - hence the expressions "method-level injection" and "method-level injection" at field level." Field-level annotations are concise and easier to use, while method-level annotations allow further handling of the injected dependency. In both cases, the visibility of the member (public, protected, or private) does not matter.

What about class-level annotations?

On the Java EE platform, they are used to declare dependencies rather than to inject resources.

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

We highly recommend If you haven't already done so, take a look at "Declarative Transaction Management" for more detailed explanations regarding declarative transactions in 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.

As a direct alternative, Spring's native 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 to DataAccessExceptions 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 specialized DataSource 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 as jpaProperties for the LocalContainerEntityManagerFactoryBean. 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 the hibernate.connection.handling_modeproperty from Hibernate 5.2 to DELAYED_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 declared LocalContainerEntityManagerFactoryBean). The server-provided EntityManagerFactory 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.