Split files
This commit is contained in:
108
framework-docs/modules/ROOT/pages/data-access/orm/general.adoc
Normal file
108
framework-docs/modules/ROOT/pages/data-access/orm/general.adoc
Normal file
@@ -0,0 +1,108 @@
|
||||
[[orm-general]]
|
||||
= General ORM Integration Considerations
|
||||
|
||||
This section highlights considerations that apply to all ORM technologies.
|
||||
The <<orm-hibernate>> section provides more details and also show these features and
|
||||
configurations in a concrete context.
|
||||
|
||||
The major goal of Spring's ORM integration is clear application layering (with any data
|
||||
access and transaction technology) and for loose coupling of application objects -- no
|
||||
more business service dependencies on the data access or transaction strategy, no more
|
||||
hard-coded resource lookups, no more hard-to-replace singletons, no more custom service
|
||||
registries. The goal is to have one simple and consistent approach to wiring up application objects, keeping
|
||||
them as reusable and free from container dependencies as possible. All the individual
|
||||
data access features are usable on their own but integrate nicely with Spring's
|
||||
application context concept, providing XML-based configuration and cross-referencing of
|
||||
plain JavaBean instances that need not be Spring-aware. In a typical Spring application,
|
||||
many important objects are JavaBeans: data access templates, data access objects,
|
||||
transaction managers, business services that use the data access objects and transaction
|
||||
managers, web view resolvers, web controllers that use the business services, and so on.
|
||||
|
||||
|
||||
[[orm-resource-mngmnt]]
|
||||
== Resource and Transaction Management
|
||||
|
||||
Typical business applications are cluttered with repetitive resource management code.
|
||||
Many projects try to invent their own solutions, sometimes sacrificing proper handling
|
||||
of failures for programming convenience. Spring advocates simple solutions for proper
|
||||
resource handling, namely IoC through templating in the case of JDBC and applying AOP
|
||||
interceptors for the ORM technologies.
|
||||
|
||||
The infrastructure provides proper resource handling and appropriate conversion of
|
||||
specific API exceptions to an unchecked infrastructure exception hierarchy. Spring
|
||||
introduces a DAO exception hierarchy, applicable to any data access strategy. For direct
|
||||
JDBC, the `JdbcTemplate` class mentioned in a <<jdbc-JdbcTemplate, previous section>>
|
||||
provides connection handling and proper conversion of `SQLException` to the
|
||||
`DataAccessException` hierarchy, including translation of database-specific SQL error
|
||||
codes to meaningful exception classes. For ORM technologies, see the
|
||||
<<orm-exception-translation, next section>> for how to get the same exception
|
||||
translation benefits.
|
||||
|
||||
When it comes to transaction management, the `JdbcTemplate` class hooks in to the Spring
|
||||
transaction support and supports both JTA and JDBC transactions, through respective
|
||||
Spring transaction managers. For the supported ORM technologies, Spring offers Hibernate
|
||||
and JPA support through the Hibernate and JPA transaction managers as well as JTA support.
|
||||
For details on transaction support, see the <<transaction>> chapter.
|
||||
|
||||
|
||||
[[orm-exception-translation]]
|
||||
== Exception Translation
|
||||
|
||||
When you use Hibernate or JPA in a DAO, you must decide how to handle the persistence
|
||||
technology's native exception classes. The DAO throws a subclass of a `HibernateException`
|
||||
or `PersistenceException`, depending on the technology. These exceptions are all runtime
|
||||
exceptions and do not have to be declared or caught. You may also have to deal with
|
||||
`IllegalArgumentException` and `IllegalStateException`. This means that callers can only
|
||||
treat exceptions as being generally fatal, unless they want to depend on the persistence
|
||||
technology's own exception structure. Catching specific causes (such as an optimistic
|
||||
locking failure) is not possible without tying the caller to the implementation strategy.
|
||||
This trade-off might be acceptable to applications that are strongly ORM-based or
|
||||
do not need any special exception treatment (or both). However, Spring lets exception
|
||||
translation be applied transparently through the `@Repository` annotation. The following
|
||||
examples (one for Java configuration and one for XML configuration) show how to do so:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
@Repository
|
||||
public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
// class body here...
|
||||
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
@Repository
|
||||
class ProductDaoImpl : ProductDao {
|
||||
|
||||
// class body here...
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<!-- Exception translation bean post processor -->
|
||||
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl"/>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
The postprocessor automatically looks for all exception translators (implementations of
|
||||
the `PersistenceExceptionTranslator` interface) and advises all beans marked with the
|
||||
`@Repository` annotation so that the discovered translators can intercept and apply the
|
||||
appropriate translation on the thrown exceptions.
|
||||
|
||||
In summary, you can implement DAOs based on the plain persistence technology's API and
|
||||
annotations while still benefiting from Spring-managed transactions, dependency
|
||||
injection, and transparent exception conversion (if desired) to Spring's custom
|
||||
exception hierarchies.
|
||||
|
||||
|
||||
|
||||
490
framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc
Normal file
490
framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc
Normal file
@@ -0,0 +1,490 @@
|
||||
[[orm-hibernate]]
|
||||
= Hibernate
|
||||
|
||||
We start with a coverage of https://hibernate.org/[Hibernate 5] in a Spring environment,
|
||||
using it to demonstrate the approach that Spring takes towards integrating OR mappers.
|
||||
This section covers many issues in detail and shows different variations of DAO
|
||||
implementations and transaction demarcation. Most of these patterns can be directly
|
||||
translated to all other supported ORM tools. The later sections in this chapter then
|
||||
cover the other ORM technologies and show brief examples.
|
||||
|
||||
NOTE: As of Spring Framework 5.3, Spring requires Hibernate ORM 5.2+ for Spring's
|
||||
`HibernateJpaVendorAdapter` as well as for a native Hibernate `SessionFactory` setup.
|
||||
It is strongly recommended to go with Hibernate ORM 5.4 for a newly started application.
|
||||
For use with `HibernateJpaVendorAdapter`, Hibernate Search needs to be upgraded to 5.11.6.
|
||||
|
||||
|
||||
[[orm-session-factory-setup]]
|
||||
== `SessionFactory` Setup in a Spring Container
|
||||
|
||||
To avoid tying application objects to hard-coded resource lookups, you can define
|
||||
resources (such as a JDBC `DataSource` or a Hibernate `SessionFactory`) as beans in the
|
||||
Spring container. Application objects that need to access resources receive references
|
||||
to such predefined instances through bean references, as illustrated in the DAO
|
||||
definition in the <<orm-hibernate-straight, next section>>.
|
||||
|
||||
The following excerpt from an XML application context definition shows how to set up a
|
||||
JDBC `DataSource` and a Hibernate `SessionFactory` on top of it:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
|
||||
<property name="username" value="sa"/>
|
||||
<property name="password" value=""/>
|
||||
</bean>
|
||||
|
||||
<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
|
||||
<property name="dataSource" ref="myDataSource"/>
|
||||
<property name="mappingResources">
|
||||
<list>
|
||||
<value>product.hbm.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="hibernateProperties">
|
||||
<value>
|
||||
hibernate.dialect=org.hibernate.dialect.HSQLDialect
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
Switching from a local Jakarta Commons DBCP `BasicDataSource` to a JNDI-located
|
||||
`DataSource` (usually managed by an application server) is only a matter of
|
||||
configuration, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>
|
||||
</beans>
|
||||
----
|
||||
|
||||
You can also access a JNDI-located `SessionFactory`, using Spring's
|
||||
`JndiObjectFactoryBean` / `<jee:jndi-lookup>` to retrieve and expose it.
|
||||
However, that is typically not common outside of an EJB context.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Spring also provides a `LocalSessionFactoryBuilder` variant, seamlessly integrating
|
||||
with `@Bean` style configuration and programmatic setup (no `FactoryBean` involved).
|
||||
|
||||
Both `LocalSessionFactoryBean` and `LocalSessionFactoryBuilder` support background
|
||||
bootstrapping, with Hibernate initialization running in parallel to the application
|
||||
bootstrap thread on a given bootstrap executor (such as a `SimpleAsyncTaskExecutor`).
|
||||
On `LocalSessionFactoryBean`, this is available through the `bootstrapExecutor`
|
||||
property. On the programmatic `LocalSessionFactoryBuilder`, there is an overloaded
|
||||
`buildSessionFactory` method that takes a bootstrap executor argument.
|
||||
|
||||
As of Spring Framework 5.1, such a native Hibernate setup can also expose a JPA
|
||||
`EntityManagerFactory` for standard JPA interaction next to native Hibernate access.
|
||||
See <<orm-jpa-hibernate, Native Hibernate Setup for JPA>> for details.
|
||||
====
|
||||
|
||||
|
||||
[[orm-hibernate-straight]]
|
||||
== Implementing DAOs Based on the Plain Hibernate API
|
||||
|
||||
Hibernate has a feature called contextual sessions, wherein Hibernate itself manages
|
||||
one current `Session` per transaction. This is roughly equivalent to Spring's
|
||||
synchronization of one Hibernate `Session` per transaction. A corresponding DAO
|
||||
implementation resembles the following example, based on the plain Hibernate API:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
public Collection loadProductsByCategory(String category) {
|
||||
return this.sessionFactory.getCurrentSession()
|
||||
.createQuery("from test.Product product where product.category=?")
|
||||
.setParameter(0, category)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao {
|
||||
|
||||
fun loadProductsByCategory(category: String): Collection<*> {
|
||||
return sessionFactory.currentSession
|
||||
.createQuery("from test.Product product where product.category=?")
|
||||
.setParameter(0, category)
|
||||
.list()
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This style is similar to that of the Hibernate reference documentation and examples,
|
||||
except for holding the `SessionFactory` in an instance variable. We strongly recommend
|
||||
such an instance-based setup over the old-school `static` `HibernateUtil` class from
|
||||
Hibernate's CaveatEmptor sample application. (In general, do not keep any resources in
|
||||
`static` variables unless absolutely necessary.)
|
||||
|
||||
The preceding DAO example follows the dependency injection pattern. It fits nicely into a Spring IoC
|
||||
container, as it would if coded against Spring's `HibernateTemplate`.
|
||||
You can also set up such a DAO in plain Java (for example, in unit tests). To do so,
|
||||
instantiate it and call `setSessionFactory(..)` with the desired factory reference. As a
|
||||
Spring bean definition, the DAO would resemble the following:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl">
|
||||
<property name="sessionFactory" ref="mySessionFactory"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
The main advantage of this DAO style is that it depends on Hibernate API only. No import
|
||||
of any Spring class is required. This is appealing from a non-invasiveness
|
||||
perspective and may feel more natural to Hibernate developers.
|
||||
|
||||
However, the DAO throws plain `HibernateException` (which is unchecked, so it does not have
|
||||
to be declared or caught), which means that callers can treat exceptions only as being
|
||||
generally fatal -- unless they want to depend on Hibernate's own exception hierarchy.
|
||||
Catching specific causes (such as an optimistic locking failure) is not possible without
|
||||
tying the caller to the implementation strategy. This trade off might be acceptable to
|
||||
applications that are strongly Hibernate-based, do not need any special exception
|
||||
treatment, or both.
|
||||
|
||||
Fortunately, Spring's `LocalSessionFactoryBean` supports Hibernate's
|
||||
`SessionFactory.getCurrentSession()` method for any Spring transaction strategy,
|
||||
returning the current Spring-managed transactional `Session`, even with
|
||||
`HibernateTransactionManager`. The standard behavior of that method remains
|
||||
to return the current `Session` associated with the ongoing JTA transaction, if any.
|
||||
This behavior applies regardless of whether you use Spring's
|
||||
`JtaTransactionManager`, EJB container managed transactions (CMTs), or JTA.
|
||||
|
||||
In summary, you can implement DAOs based on the plain Hibernate API, while still being
|
||||
able to participate in Spring-managed transactions.
|
||||
|
||||
|
||||
[[orm-hibernate-tx-declarative]]
|
||||
== Declarative Transaction Demarcation
|
||||
|
||||
We recommend that you use Spring's declarative transaction support, which lets you
|
||||
replace explicit transaction demarcation API calls in your Java code with an AOP
|
||||
transaction interceptor. You can configure this transaction interceptor in a Spring
|
||||
container by using either Java annotations or XML. This declarative transaction capability
|
||||
lets you keep business services free of repetitive transaction demarcation code and
|
||||
focus on adding business logic, which is the real value of your application.
|
||||
|
||||
NOTE: Before you continue, we are strongly encourage you to read <<transaction-declarative>>
|
||||
if you have not already done so.
|
||||
|
||||
You can annotate the service layer with `@Transactional` annotations and instruct the
|
||||
Spring container to find these annotations and provide transactional semantics for
|
||||
these annotated methods. The following example shows how to do so:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
public class ProductServiceImpl implements ProductService {
|
||||
|
||||
private ProductDao productDao;
|
||||
|
||||
public void setProductDao(ProductDao productDao) {
|
||||
this.productDao = productDao;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void increasePriceOfAllProductsInCategory(final String category) {
|
||||
List productsToChange = this.productDao.loadProductsByCategory(category);
|
||||
// ...
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Product> findAllProducts() {
|
||||
return this.productDao.findAllProducts();
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
class ProductServiceImpl(private val productDao: ProductDao) : ProductService {
|
||||
|
||||
@Transactional
|
||||
fun increasePriceOfAllProductsInCategory(category: String) {
|
||||
val productsToChange = productDao.loadProductsByCategory(category)
|
||||
// ...
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findAllProducts() = productDao.findAllProducts()
|
||||
}
|
||||
----
|
||||
|
||||
In the container, you need to set up the `PlatformTransactionManager` implementation
|
||||
(as a bean) and a `<tx:annotation-driven/>` entry, opting into `@Transactional`
|
||||
processing at runtime. The following example shows how to do so:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/tx
|
||||
https://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
https://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
|
||||
<!-- SessionFactory, DataSource, etc. omitted -->
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
|
||||
<property name="sessionFactory" ref="sessionFactory"/>
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven/>
|
||||
|
||||
<bean id="myProductService" class="product.SimpleProductService">
|
||||
<property name="productDao" ref="myProductDao"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
|
||||
[[orm-hibernate-tx-programmatic]]
|
||||
== Programmatic Transaction Demarcation
|
||||
|
||||
You can demarcate transactions in a higher level of the application, on top of
|
||||
lower-level data access services that span any number of operations. Nor do restrictions
|
||||
exist on the implementation of the surrounding business service. It needs only a Spring
|
||||
`PlatformTransactionManager`. Again, the latter can come from anywhere, but preferably
|
||||
as a bean reference through a `setTransactionManager(..)` method. Also, the
|
||||
`productDAO` should be set by a `setProductDao(..)` method. The following pair of snippets show
|
||||
a transaction manager and a business service definition in a Spring application context
|
||||
and an example for a business method implementation:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<bean id="myTxManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
|
||||
<property name="sessionFactory" ref="mySessionFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="myProductService" class="product.ProductServiceImpl">
|
||||
<property name="transactionManager" ref="myTxManager"/>
|
||||
<property name="productDao" ref="myProductDao"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
public class ProductServiceImpl implements ProductService {
|
||||
|
||||
private TransactionTemplate transactionTemplate;
|
||||
private ProductDao productDao;
|
||||
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
}
|
||||
|
||||
public void setProductDao(ProductDao productDao) {
|
||||
this.productDao = productDao;
|
||||
}
|
||||
|
||||
public void increasePriceOfAllProductsInCategory(final String category) {
|
||||
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
List productsToChange = this.productDao.loadProductsByCategory(category);
|
||||
// do the price increase...
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
class ProductServiceImpl(transactionManager: PlatformTransactionManager,
|
||||
private val productDao: ProductDao) : ProductService {
|
||||
|
||||
private val transactionTemplate = TransactionTemplate(transactionManager)
|
||||
|
||||
fun increasePriceOfAllProductsInCategory(category: String) {
|
||||
transactionTemplate.execute {
|
||||
val productsToChange = productDao.loadProductsByCategory(category)
|
||||
// do the price increase...
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Spring's `TransactionInterceptor` lets any checked application exception be thrown
|
||||
with the callback code, while `TransactionTemplate` is restricted to unchecked
|
||||
exceptions within the callback. `TransactionTemplate` triggers a rollback in case of
|
||||
an unchecked application exception or if the transaction is marked rollback-only by
|
||||
the application (by setting `TransactionStatus`). By default, `TransactionInterceptor`
|
||||
behaves the same way but allows configurable rollback policies per method.
|
||||
|
||||
|
||||
[[orm-hibernate-tx-strategies]]
|
||||
== Transaction Management Strategies
|
||||
|
||||
Both `TransactionTemplate` and `TransactionInterceptor` delegate the actual transaction
|
||||
handling to a `PlatformTransactionManager` instance (which can be a
|
||||
`HibernateTransactionManager` (for a single Hibernate `SessionFactory`) by using a
|
||||
`ThreadLocal` `Session` under the hood) or a `JtaTransactionManager` (delegating to the
|
||||
JTA subsystem of the container) for Hibernate applications. You can even use a custom
|
||||
`PlatformTransactionManager` implementation. Switching from native Hibernate transaction
|
||||
management to JTA (such as when facing distributed transaction requirements for certain
|
||||
deployments of your application) is only a matter of configuration. You can replace
|
||||
the Hibernate transaction manager with Spring's JTA transaction implementation. Both
|
||||
transaction demarcation and data access code work without changes, because they
|
||||
use the generic transaction management APIs.
|
||||
|
||||
For distributed transactions across multiple Hibernate session factories, you can combine
|
||||
`JtaTransactionManager` as a transaction strategy with multiple
|
||||
`LocalSessionFactoryBean` definitions. Each DAO then gets one specific `SessionFactory`
|
||||
reference passed into its corresponding bean property. If all underlying JDBC data
|
||||
sources are transactional container ones, a business service can demarcate transactions
|
||||
across any number of DAOs and any number of session factories without special regard, as
|
||||
long as it uses `JtaTransactionManager` as the strategy.
|
||||
|
||||
Both `HibernateTransactionManager` and `JtaTransactionManager` allow for proper
|
||||
JVM-level cache handling with Hibernate, without container-specific transaction manager
|
||||
lookup or a JCA connector (if you do not use EJB to initiate transactions).
|
||||
|
||||
`HibernateTransactionManager` can export the Hibernate JDBC `Connection` to plain JDBC
|
||||
access code for a specific `DataSource`. This ability allows for high-level
|
||||
transaction demarcation with mixed Hibernate and JDBC data access completely without
|
||||
JTA, provided you access only one database. `HibernateTransactionManager` automatically
|
||||
exposes the Hibernate transaction as a JDBC transaction if you have set up the passed-in
|
||||
`SessionFactory` with a `DataSource` through the `dataSource` property of the
|
||||
`LocalSessionFactoryBean` class. Alternatively, you can specify explicitly the
|
||||
`DataSource` for which the transactions are supposed to be exposed through the
|
||||
`dataSource` property of the `HibernateTransactionManager` class.
|
||||
|
||||
|
||||
[[orm-hibernate-resources]]
|
||||
== Comparing Container-managed and Locally Defined Resources
|
||||
|
||||
You can switch between a container-managed JNDI `SessionFactory` and a locally defined
|
||||
one without having to change a single line of application code. Whether to keep
|
||||
resource definitions in the container or locally within the application is mainly a
|
||||
matter of the transaction strategy that you use. Compared to a Spring-defined local
|
||||
`SessionFactory`, a manually registered JNDI `SessionFactory` does not provide any
|
||||
benefits. Deploying a `SessionFactory` through Hibernate's JCA connector provides the
|
||||
added value of participating in the Jakarta EE server's management infrastructure, but does
|
||||
not add actual value beyond that.
|
||||
|
||||
Spring's transaction support is not bound to a container. When configured with any strategy
|
||||
other than JTA, transaction support also works in a stand-alone or test environment.
|
||||
Especially in the typical case of single-database transactions, Spring's single-resource
|
||||
local transaction support is a lightweight and powerful alternative to JTA. When you use
|
||||
local EJB stateless session beans to drive transactions, you depend both on an EJB
|
||||
container and on JTA, even if you access only a single database and use only stateless
|
||||
session beans to provide declarative transactions through container-managed
|
||||
transactions. Direct use of JTA programmatically also requires a Jakarta EE environment.
|
||||
|
||||
Spring-driven transactions can work as well with a locally defined Hibernate
|
||||
`SessionFactory` as they do with a local JDBC `DataSource`, provided they access a
|
||||
single database. Thus, you need only use Spring's JTA transaction strategy when you
|
||||
have distributed transaction requirements. A JCA connector requires container-specific
|
||||
deployment steps, and (obviously) JCA support in the first place. This configuration
|
||||
requires more work than deploying a simple web application with local resource
|
||||
definitions and Spring-driven transactions.
|
||||
|
||||
All things considered, if you do not use EJBs, stick with local `SessionFactory` setup
|
||||
and Spring's `HibernateTransactionManager` or `JtaTransactionManager`. You get all of
|
||||
the benefits, including proper transactional JVM-level caching and distributed
|
||||
transactions, without the inconvenience of container deployment. JNDI registration of a
|
||||
Hibernate `SessionFactory` through the JCA connector adds value only when used in
|
||||
conjunction with EJBs.
|
||||
|
||||
|
||||
[[orm-hibernate-invalid-jdbc-access-error]]
|
||||
== Spurious Application Server Warnings with Hibernate
|
||||
|
||||
In some JTA environments with very strict `XADataSource` implementations (currently
|
||||
some WebLogic Server and WebSphere versions), when Hibernate is configured without
|
||||
regard to the JTA transaction manager for that environment, spurious warnings or
|
||||
exceptions can show up in the application server log. These warnings or exceptions
|
||||
indicate that the connection being accessed is no longer valid or JDBC access is no
|
||||
longer valid, possibly because the transaction is no longer active. As an example,
|
||||
here is an actual exception from WebLogic:
|
||||
|
||||
[literal]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
java.sql.SQLException: The transaction is no longer active - status: 'Committed'. No
|
||||
further JDBC access is allowed within this transaction.
|
||||
----
|
||||
|
||||
Another common problem is a connection leak after JTA transactions, with Hibernate
|
||||
sessions (and potentially underlying JDBC connections) not getting closed properly.
|
||||
|
||||
You can resolve such issues by making Hibernate aware of the JTA transaction manager,
|
||||
to which it synchronizes (along with Spring). You have two options for doing this:
|
||||
|
||||
* Pass your Spring `JtaTransactionManager` bean to your Hibernate setup. The easiest
|
||||
way is a bean reference into the `jtaTransactionManager` property for your
|
||||
`LocalSessionFactoryBean` bean (see <<transaction-strategies-hibernate>>).
|
||||
Spring then makes the corresponding JTA strategies available to Hibernate.
|
||||
* You may also configure Hibernate's JTA-related properties explicitly, in particular
|
||||
"hibernate.transaction.coordinator_class", "hibernate.connection.handling_mode"
|
||||
and potentially "hibernate.transaction.jta.platform" in your "hibernateProperties"
|
||||
on `LocalSessionFactoryBean` (see Hibernate's manual for details on those properties).
|
||||
|
||||
The remainder of this section describes the sequence of events that occur with and
|
||||
without Hibernate's awareness of the JTA `PlatformTransactionManager`.
|
||||
|
||||
When Hibernate is not configured with any awareness of the JTA transaction manager,
|
||||
the following events occur when a JTA transaction commits:
|
||||
|
||||
* The JTA transaction commits.
|
||||
* Spring's `JtaTransactionManager` is synchronized to the JTA transaction, so it is
|
||||
called back through an `afterCompletion` callback by the JTA transaction manager.
|
||||
* Among other activities, this synchronization can trigger a callback by Spring to
|
||||
Hibernate, through Hibernate's `afterTransactionCompletion` callback (used to clear
|
||||
the Hibernate cache), followed by an explicit `close()` call on the Hibernate session,
|
||||
which causes Hibernate to attempt to `close()` the JDBC Connection.
|
||||
* In some environments, this `Connection.close()` call then triggers the warning or
|
||||
error, as the application server no longer considers the `Connection` to be usable,
|
||||
because the transaction has already been committed.
|
||||
|
||||
When Hibernate is configured with awareness of the JTA transaction manager,
|
||||
the following events occur when a JTA transaction commits:
|
||||
|
||||
* The JTA transaction is ready to commit.
|
||||
* Spring's `JtaTransactionManager` is synchronized to the JTA transaction, so the
|
||||
transaction is called back through a `beforeCompletion` callback by the JTA
|
||||
transaction manager.
|
||||
* Spring is aware that Hibernate itself is synchronized to the JTA transaction and
|
||||
behaves differently than in the previous scenario. In particular, it aligns with
|
||||
Hibernate's transactional resource management.
|
||||
* The JTA transaction commits.
|
||||
* Hibernate is synchronized to the JTA transaction, so the transaction is called back
|
||||
through an `afterCompletion` callback by the JTA transaction manager and can
|
||||
properly clear its cache.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
[[orm-introduction]]
|
||||
= Introduction to ORM with Spring
|
||||
|
||||
The Spring Framework supports integration with the Java Persistence API (JPA) and
|
||||
supports native Hibernate for resource management, data access object (DAO) implementations,
|
||||
and transaction strategies. For example, for Hibernate, there is first-class support with
|
||||
several convenient IoC features that address many typical Hibernate integration issues.
|
||||
You can configure all of the supported features for OR (object relational) mapping
|
||||
tools through Dependency Injection. They can participate in Spring's resource and
|
||||
transaction management, and they comply with Spring's generic transaction and DAO
|
||||
exception hierarchies. The recommended integration style is to code DAOs against plain
|
||||
Hibernate or JPA APIs.
|
||||
|
||||
Spring adds significant enhancements to the ORM layer of your choice when you create
|
||||
data access applications. You can leverage as much of the integration support as you
|
||||
wish, and you should compare this integration effort with the cost and risk of building
|
||||
a similar infrastructure in-house. You can use much of the ORM support as you would a
|
||||
library, regardless of technology, because everything is designed as a set of reusable
|
||||
JavaBeans. ORM in a Spring IoC container facilitates configuration and deployment. Thus,
|
||||
most examples in this section show configuration inside a Spring container.
|
||||
|
||||
The benefits of using the Spring Framework to create your ORM DAOs include:
|
||||
|
||||
* *Easier testing.* Spring's IoC approach makes it easy to swap the implementations
|
||||
and configuration locations of Hibernate `SessionFactory` instances, JDBC `DataSource`
|
||||
instances, transaction managers, and mapped object implementations (if needed). This
|
||||
in turn makes it much easier to test each piece of persistence-related code in
|
||||
isolation.
|
||||
* *Common data access exceptions.* Spring can wrap exceptions from your ORM tool,
|
||||
converting them from proprietary (potentially checked) exceptions to a common runtime
|
||||
`DataAccessException` hierarchy. This feature lets you handle most persistence
|
||||
exceptions, which are non-recoverable, only in the appropriate layers, without
|
||||
annoying boilerplate catches, throws, and exception declarations. You can still trap
|
||||
and handle exceptions as necessary. Remember that JDBC exceptions (including
|
||||
DB-specific dialects) are also converted to the same hierarchy, meaning that you can
|
||||
perform some operations with JDBC within a consistent programming model.
|
||||
* *General resource management.* Spring application contexts can handle the location
|
||||
and configuration of Hibernate `SessionFactory` instances, JPA `EntityManagerFactory`
|
||||
instances, JDBC `DataSource` instances, and other related resources. This makes these
|
||||
values easy to manage and change. Spring offers efficient, easy, and safe handling of
|
||||
persistence resources. For example, related code that uses Hibernate generally needs to
|
||||
use the same Hibernate `Session` to ensure efficiency and proper transaction handling.
|
||||
Spring makes it easy to create and bind a `Session` to the current thread transparently,
|
||||
by exposing a current `Session` through the Hibernate `SessionFactory`. Thus, Spring
|
||||
solves many chronic problems of typical Hibernate usage, for any local or JTA
|
||||
transaction environment.
|
||||
* *Integrated transaction management.* You can wrap your ORM code with a declarative,
|
||||
aspect-oriented programming (AOP) style method interceptor either through the
|
||||
`@Transactional` annotation or by explicitly configuring the transaction AOP advice in
|
||||
an XML configuration file. In both cases, transaction semantics and exception handling
|
||||
(rollback and so on) are handled for you. As discussed in <<orm-resource-mngmnt>>,
|
||||
you can also swap various transaction managers, without affecting your ORM-related code.
|
||||
For example, you can swap between local transactions and JTA, with the same full services
|
||||
(such as declarative transactions) available in both scenarios. Additionally,
|
||||
JDBC-related code can fully integrate transactionally with the code you use to do ORM.
|
||||
This is useful for data access that is not suitable for ORM (such as batch processing and
|
||||
BLOB streaming) but that still needs to share common transactions with ORM operations.
|
||||
|
||||
TIP: For more comprehensive ORM support, including support for alternative database
|
||||
technologies such as MongoDB, you might want to check out the
|
||||
https://projects.spring.io/spring-data/[Spring Data] suite of projects. If you are
|
||||
a JPA user, the https://spring.io/guides/gs/accessing-data-jpa/[Getting Started Accessing
|
||||
Data with JPA] guide from https://spring.io provides a great introduction.
|
||||
|
||||
|
||||
|
||||
577
framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc
Normal file
577
framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc
Normal file
@@ -0,0 +1,577 @@
|
||||
[[orm-jpa]]
|
||||
= JPA
|
||||
|
||||
The Spring JPA, available under the `org.springframework.orm.jpa` package, offers
|
||||
comprehensive support for the
|
||||
https://www.oracle.com/technetwork/articles/javaee/jpa-137156.html[Java Persistence
|
||||
API] in a manner similar to the integration with Hibernate while being aware of
|
||||
the underlying implementation in order to provide additional features.
|
||||
|
||||
|
||||
[[orm-jpa-setup]]
|
||||
== Three Options for JPA Setup in a Spring Environment
|
||||
|
||||
The Spring JPA support offers three ways of setting up the JPA `EntityManagerFactory`
|
||||
that is used by the application to obtain an entity manager.
|
||||
|
||||
* <<orm-jpa-setup-lemfb>>
|
||||
* <<orm-jpa-setup-jndi>>
|
||||
* <<orm-jpa-setup-lcemfb>>
|
||||
|
||||
[[orm-jpa-setup-lemfb]]
|
||||
=== Using `LocalEntityManagerFactoryBean`
|
||||
|
||||
You can use this option only in simple deployment environments such as stand-alone
|
||||
applications and integration tests.
|
||||
|
||||
The `LocalEntityManagerFactoryBean` creates an `EntityManagerFactory` suitable for
|
||||
simple deployment environments where the application uses only JPA for data access.
|
||||
The factory bean uses the JPA `PersistenceProvider` auto-detection mechanism (according
|
||||
to JPA's Java SE bootstrapping) and, in most cases, requires you to specify only the
|
||||
persistence unit name. The following XML example configures such a bean:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<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 the most limited. You cannot refer to an
|
||||
existing JDBC `DataSource` bean definition, and no support for global transactions
|
||||
exists. Furthermore, weaving (byte-code transformation) of persistent classes is
|
||||
provider-specific, often requiring a specific JVM agent to be specified on startup. This
|
||||
option is sufficient only for stand-alone applications and test environments, for which
|
||||
the JPA specification is designed.
|
||||
|
||||
[[orm-jpa-setup-jndi]]
|
||||
=== Obtaining an EntityManagerFactory from JNDI
|
||||
|
||||
You can use this option when deploying to a Jakarta EE server. Check your server's documentation
|
||||
on how to deploy a custom JPA provider into your server, allowing for a different
|
||||
provider than the server's default.
|
||||
|
||||
Obtaining an `EntityManagerFactory` from JNDI (for example in a Jakarta EE environment),
|
||||
is a matter of changing the XML configuration, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
|
||||
</beans>
|
||||
----
|
||||
|
||||
This action assumes standard Jakarta EE bootstrapping. The Jakarta EE server auto-detects
|
||||
persistence units (in effect, `META-INF/persistence.xml` files in application jars) and
|
||||
`persistence-unit-ref` entries in the Jakarta EE deployment descriptor (for example,
|
||||
`web.xml`) and defines environment naming context locations for those persistence units.
|
||||
|
||||
In such a scenario, the entire persistence unit deployment, including the weaving
|
||||
(byte-code transformation) of persistent classes, is up to the Jakarta EE server. The JDBC
|
||||
`DataSource` is defined through a JNDI location in the `META-INF/persistence.xml` file.
|
||||
`EntityManager` transactions are integrated with the server's JTA subsystem. Spring merely
|
||||
uses the obtained `EntityManagerFactory`, passing it on to application objects through
|
||||
dependency injection and managing transactions for the persistence unit (typically
|
||||
through `JtaTransactionManager`).
|
||||
|
||||
If you use multiple persistence units in the same application, the bean names of such
|
||||
JNDI-retrieved persistence units should match the persistence unit names that the
|
||||
application uses to refer to them (for example, in `@PersistenceUnit` and
|
||||
`@PersistenceContext` annotations).
|
||||
|
||||
[[orm-jpa-setup-lcemfb]]
|
||||
=== Using `LocalContainerEntityManagerFactoryBean`
|
||||
|
||||
You can use this option for full JPA capabilities in a Spring-based application environment.
|
||||
This includes web containers such as Tomcat, stand-alone applications, and
|
||||
integration tests with sophisticated persistence requirements.
|
||||
|
||||
NOTE: If you want to specifically configure a Hibernate setup, an immediate alternative
|
||||
is to set up a native Hibernate `LocalSessionFactoryBean` instead of a plain JPA
|
||||
`LocalContainerEntityManagerFactoryBean`, letting it interact with JPA access code
|
||||
as well as native Hibernate access code.
|
||||
See <<orm-jpa-hibernate, Native Hibernate setup for JPA interaction>> for details.
|
||||
|
||||
The `LocalContainerEntityManagerFactoryBean` gives full control over
|
||||
`EntityManagerFactory` configuration and is appropriate for environments where
|
||||
fine-grained customization is required. The `LocalContainerEntityManagerFactoryBean`
|
||||
creates a `PersistenceUnitInfo` instance based on the `persistence.xml` file, the
|
||||
supplied `dataSourceLookup` strategy, and the specified `loadTimeWeaver`. It is, thus,
|
||||
possible to work with custom data sources outside of JNDI and to control the weaving
|
||||
process. The following example shows a typical bean definition for a
|
||||
`LocalContainerEntityManagerFactoryBean`:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<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:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
NOTE: The `<exclude-unlisted-classes/>` shortcut indicates that no scanning for
|
||||
annotated entity classes is supposed to occur. An explicit 'true' value
|
||||
(`<exclude-unlisted-classes>true</exclude-unlisted-classes/>`) also means no scan.
|
||||
`<exclude-unlisted-classes>false</exclude-unlisted-classes/>` does trigger a scan.
|
||||
However, we recommend omitting the `exclude-unlisted-classes` element
|
||||
if you want entity class scanning to occur.
|
||||
|
||||
Using the `LocalContainerEntityManagerFactoryBean` is the most powerful JPA setup
|
||||
option, allowing for flexible local configuration within the application. It supports
|
||||
links to an existing JDBC `DataSource`, supports both local and global transactions, and
|
||||
so on. However, it also imposes requirements on the runtime environment, such as the
|
||||
availability of a weaving-capable class loader if the persistence provider demands
|
||||
byte-code transformation.
|
||||
|
||||
This option may conflict with the built-in JPA capabilities of a Jakarta EE server. In a
|
||||
full Jakarta EE environment, consider obtaining your `EntityManagerFactory` from JNDI.
|
||||
Alternatively, specify a custom `persistenceXmlLocation` on your
|
||||
`LocalContainerEntityManagerFactoryBean` definition (for example,
|
||||
META-INF/my-persistence.xml) and include only a descriptor with that name in your
|
||||
application jar files. Because the Jakarta EE server looks only for default
|
||||
`META-INF/persistence.xml` files, it ignores such custom persistence units and, hence,
|
||||
avoids conflicts with a Spring-driven JPA setup upfront. (This applies to Resin 3.1, for
|
||||
example.)
|
||||
|
||||
.When is load-time weaving required?
|
||||
****
|
||||
Not all JPA providers require a JVM agent. Hibernate is an example of one that does not.
|
||||
If your provider does not require an agent or you have other alternatives, such as
|
||||
applying enhancements at build time through a custom compiler or an Ant task, you should not use the
|
||||
load-time weaver.
|
||||
****
|
||||
|
||||
The `LoadTimeWeaver` interface is a Spring-provided class that lets JPA
|
||||
`ClassTransformer` instances be plugged in a specific manner, depending on whether the
|
||||
environment is a web container or application server. Hooking `ClassTransformers`
|
||||
through an
|
||||
https://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html[agent]
|
||||
is typically not efficient. The agents work against the entire virtual machine and
|
||||
inspect every class that is loaded, which is usually undesirable in a production
|
||||
server environment.
|
||||
|
||||
Spring provides a number of `LoadTimeWeaver` implementations for various environments,
|
||||
letting `ClassTransformer` instances be applied only for each class loader and not
|
||||
for each VM.
|
||||
|
||||
See the <<core.adoc#aop-aj-ltw-spring, Spring configuration>> in the AOP chapter for
|
||||
more insight regarding the `LoadTimeWeaver` implementations and their setup, either
|
||||
generic or customized to various platforms (such as Tomcat, JBoss and WebSphere).
|
||||
|
||||
As described in <<core.adoc#aop-aj-ltw-spring, Spring configuration>>, you can configure
|
||||
a context-wide `LoadTimeWeaver` by using the `@EnableLoadTimeWeaving` annotation or the
|
||||
`context:load-time-weaver` XML element. Such a global weaver is automatically picked up
|
||||
by all JPA `LocalContainerEntityManagerFactoryBean` instances. The following example
|
||||
shows the preferred way of setting up a load-time weaver, delivering auto-detection
|
||||
of the platform (e.g. Tomcat's weaving-capable class loader or Spring's JVM agent)
|
||||
and automatic propagation of the weaver to all weaver-aware beans:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<context:load-time-weaver/>
|
||||
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
...
|
||||
</bean>
|
||||
----
|
||||
|
||||
However, you can, if needed, manually specify a dedicated weaver through the
|
||||
`loadTimeWeaver` property, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="loadTimeWeaver">
|
||||
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
|
||||
No matter how the LTW is configured, by using this technique, JPA applications relying on
|
||||
instrumentation can run in the target platform (for example, Tomcat) without needing an agent.
|
||||
This is especially important when the hosting applications rely on different JPA
|
||||
implementations, because the JPA transformers are applied only at the class-loader level and
|
||||
are, thus, isolated from each other.
|
||||
|
||||
[[orm-jpa-setup-multiple]]
|
||||
=== Dealing with Multiple Persistence Units
|
||||
|
||||
For applications that rely on multiple persistence units locations (stored in various
|
||||
JARS in the classpath, for example), Spring offers the `PersistenceUnitManager` to act as
|
||||
a central repository and to avoid the persistence units discovery process, which can be
|
||||
expensive. The default implementation lets multiple locations be specified. These locations are
|
||||
parsed and later retrieved through the persistence unit name. (By default, the classpath
|
||||
is searched for `META-INF/persistence.xml` files.) The following example configures
|
||||
multiple locations:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim"]
|
||||
----
|
||||
<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 no datasource is specified, use this one -->
|
||||
<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 customization of the `PersistenceUnitInfo` instances
|
||||
(before they are fed to the JPA provider) either declaratively (through its properties, which
|
||||
affect all hosted units) or programmatically (through the
|
||||
`PersistenceUnitPostProcessor`, which allows persistence unit selection). If no
|
||||
`PersistenceUnitManager` is specified, one is created and used internally by
|
||||
`LocalContainerEntityManagerFactoryBean`.
|
||||
|
||||
[[orm-jpa-setup-background]]
|
||||
=== Background Bootstrapping
|
||||
|
||||
`LocalContainerEntityManagerFactoryBean` supports background bootstrapping through
|
||||
the `bootstrapExecutor` property, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<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 bootstrapping is handed off to the specified executor and then,
|
||||
running in parallel, to the application bootstrap thread. The exposed `EntityManagerFactory`
|
||||
proxy can be injected into other application components and is even able to respond to
|
||||
`EntityManagerFactoryInfo` configuration inspection. However, once the actual JPA provider
|
||||
is being accessed by other components (for example, calling `createEntityManager`), those calls
|
||||
block until the background bootstrapping has completed. In particular, when you use
|
||||
Spring Data JPA, make sure to set up deferred bootstrapping for its repositories as well.
|
||||
|
||||
|
||||
[[orm-jpa-dao]]
|
||||
== Implementing DAOs Based on JPA: `EntityManagerFactory` and `EntityManager`
|
||||
|
||||
NOTE: Although `EntityManagerFactory` instances are thread-safe, `EntityManager` instances are
|
||||
not. The injected JPA `EntityManager` behaves like an `EntityManager` fetched from an
|
||||
application server's JNDI environment, as defined by the JPA specification. It delegates
|
||||
all calls to the current transactional `EntityManager`, if any. Otherwise, it falls back
|
||||
to a newly created `EntityManager` per operation, in effect making its usage thread-safe.
|
||||
|
||||
It is possible to write code against the plain JPA without any Spring dependencies, by
|
||||
using an injected `EntityManagerFactory` or `EntityManager`. Spring can understand the
|
||||
`@PersistenceUnit` and `@PersistenceContext` annotations both at the field and the method level
|
||||
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain JPA DAO implementation
|
||||
that uses the `@PersistenceUnit` annotation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.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 preceding DAO has no dependency on Spring and still fits nicely into a Spring
|
||||
application context. Moreover, the DAO takes advantage of annotations to require the
|
||||
injection of the default `EntityManagerFactory`, as the following example bean definition shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<!-- bean post-processor for JPA annotations -->
|
||||
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl"/>
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
As an alternative to explicitly defining a `PersistenceAnnotationBeanPostProcessor`,
|
||||
consider using the Spring `context:annotation-config` XML element in your application
|
||||
context configuration. Doing so automatically registers all Spring standard
|
||||
post-processors for annotation-based configuration, including
|
||||
`CommonAnnotationBeanPostProcessor` and so on.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans>
|
||||
|
||||
<!-- post-processors for all standard config 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
|
||||
the factory. You can avoid this by requesting a transactional `EntityManager` (also
|
||||
called a "`shared EntityManager`" because it is a shared, thread-safe proxy for the actual
|
||||
transactional EntityManager) to be injected instead of the factory. The following example shows how to do so:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.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();
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.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 attribute called `type`, which defaults to
|
||||
`PersistenceContextType.TRANSACTION`. You can use this default to receive a shared
|
||||
`EntityManager` proxy. The alternative, `PersistenceContextType.EXTENDED`, is a completely
|
||||
different affair. This results in a so-called extended `EntityManager`, which is not
|
||||
thread-safe and, hence, must not be used in a concurrently accessed component, such as a
|
||||
Spring-managed singleton bean. Extended `EntityManager` instances are only supposed to be used in
|
||||
stateful components that, for example, reside in a session, with the lifecycle of the
|
||||
`EntityManager` not tied to a current transaction but rather being completely up to the
|
||||
application.
|
||||
|
||||
.Method- and field-level Injection
|
||||
****
|
||||
You can apply annotations that indicate dependency injections (such as `@PersistenceUnit` and
|
||||
`@PersistenceContext`) on field or methods inside a class -- hence the
|
||||
expressions "`method-level injection`" and "`field-level injection`". Field-level
|
||||
annotations are concise and easier to use while method-level annotations allow for further
|
||||
processing of the injected dependency. In both cases, the member visibility (public,
|
||||
protected, or private) does not matter.
|
||||
|
||||
What about class-level annotations?
|
||||
|
||||
On the Jakarta EE platform, they are used for dependency declaration and not for resource
|
||||
injection.
|
||||
****
|
||||
|
||||
The injected `EntityManager` is Spring-managed (aware of the ongoing transaction).
|
||||
Even though the new DAO implementation uses method-level
|
||||
injection of an `EntityManager` instead of an `EntityManagerFactory`, no change is
|
||||
required in the application context XML, due to annotation usage.
|
||||
|
||||
The main advantage of this DAO style is that it depends only on the Java Persistence API.
|
||||
No import of any Spring class is required. Moreover, as the JPA annotations are understood,
|
||||
the injections are applied automatically by the Spring container. This is appealing from
|
||||
a non-invasiveness perspective and can feel more natural to JPA developers.
|
||||
|
||||
|
||||
[[orm-jpa-tx]]
|
||||
== Spring-driven JPA transactions
|
||||
|
||||
NOTE: We strongly encourage you to read <<transaction-declarative>>, if you have not
|
||||
already done so, to get more detailed coverage of Spring's declarative transaction support.
|
||||
|
||||
The recommended strategy for JPA is local transactions through JPA's native transaction
|
||||
support. Spring's `JpaTransactionManager` provides many capabilities known from local
|
||||
JDBC transactions (such as transaction-specific isolation levels and resource-level
|
||||
read-only optimizations) against any regular JDBC connection pool (no XA requirement).
|
||||
|
||||
Spring JPA also lets a configured `JpaTransactionManager` expose a JPA transaction
|
||||
to JDBC access code that accesses the same `DataSource`, provided that the registered
|
||||
`JpaDialect` supports retrieval of the underlying JDBC `Connection`.
|
||||
Spring provides dialects for the EclipseLink and Hibernate JPA implementations.
|
||||
See the <<orm-jpa-dialect, next section>> for details on the `JpaDialect` mechanism.
|
||||
|
||||
NOTE: As an immediate alternative, Spring's native `HibernateTransactionManager` is capable
|
||||
of interacting with JPA access code, adapting to several Hibernate specifics and providing
|
||||
JDBC interaction. This makes particular sense in combination with `LocalSessionFactoryBean`
|
||||
setup. See <<orm-jpa-hibernate, Native Hibernate Setup for JPA Interaction>> for details.
|
||||
|
||||
|
||||
[[orm-jpa-dialect]]
|
||||
== Understanding `JpaDialect` and `JpaVendorAdapter`
|
||||
|
||||
As an advanced feature, `JpaTransactionManager` and subclasses of
|
||||
`AbstractEntityManagerFactoryBean` allow a custom `JpaDialect` to be passed into the
|
||||
`jpaDialect` bean property. A `JpaDialect` implementation can enable the following advanced
|
||||
features supported by Spring, usually in a vendor-specific manner:
|
||||
|
||||
* Applying specific transaction semantics (such as custom isolation level or transaction
|
||||
timeout)
|
||||
* Retrieving the transactional JDBC `Connection` (for exposure to JDBC-based DAOs)
|
||||
* Advanced translation of `PersistenceExceptions` to Spring `DataAccessExceptions`
|
||||
|
||||
This is particularly valuable for special transaction semantics and for advanced
|
||||
translation of exception. The default implementation (`DefaultJpaDialect`) does
|
||||
not provide any special abilities and, if the features listed earlier are required, you have
|
||||
to specify the appropriate dialect.
|
||||
|
||||
TIP: As an even broader provider adaptation facility primarily for Spring's full-featured
|
||||
`LocalContainerEntityManagerFactoryBean` setup, `JpaVendorAdapter` combines the
|
||||
capabilities of `JpaDialect` with other provider-specific defaults. Specifying a
|
||||
`HibernateJpaVendorAdapter` or `EclipseLinkJpaVendorAdapter` is the most convenient
|
||||
way of auto-configuring an `EntityManagerFactory` setup for Hibernate or EclipseLink,
|
||||
respectively. Note that those provider adapters are primarily designed for use with
|
||||
Spring-driven transaction management (that is, for use with `JpaTransactionManager`).
|
||||
|
||||
See the {api-spring-framework}/orm/jpa/JpaDialect.html[`JpaDialect`] and
|
||||
{api-spring-framework}/orm/jpa/JpaVendorAdapter.html[`JpaVendorAdapter`] javadoc for
|
||||
more details of its operations and how they are used within Spring's JPA support.
|
||||
|
||||
|
||||
[[orm-jpa-jta]]
|
||||
== Setting up JPA with JTA Transaction Management
|
||||
|
||||
As an alternative to `JpaTransactionManager`, Spring also allows for multi-resource
|
||||
transaction coordination through JTA, either in a Jakarta EE environment or with a
|
||||
stand-alone transaction coordinator, such as Atomikos. Aside from choosing Spring's
|
||||
`JtaTransactionManager` instead of `JpaTransactionManager`, you need to take few further
|
||||
steps:
|
||||
|
||||
* The underlying JDBC connection pools need to be XA-capable and be integrated with
|
||||
your transaction coordinator. This is usually straightforward in a Jakarta EE environment,
|
||||
exposing a different kind of `DataSource` through JNDI. See your application server
|
||||
documentation for details. Analogously, a standalone transaction coordinator usually
|
||||
comes with special XA-integrated `DataSource` variants. Again, check its documentation.
|
||||
|
||||
* The JPA `EntityManagerFactory` setup needs to be configured for JTA. This is
|
||||
provider-specific, typically through special properties to be specified as `jpaProperties`
|
||||
on `LocalContainerEntityManagerFactoryBean`. In the case of Hibernate, these properties
|
||||
are even version-specific. See your Hibernate documentation for details.
|
||||
|
||||
* Spring's `HibernateJpaVendorAdapter` enforces certain Spring-oriented defaults, such
|
||||
as the connection release mode, `on-close`, which matches Hibernate's own default in
|
||||
Hibernate 5.0 but not any more in Hibernate 5.1+. For a JTA setup, make sure to declare
|
||||
your persistence unit transaction type as "JTA". Alternatively, set Hibernate 5.2's
|
||||
`hibernate.connection.handling_mode` property to
|
||||
`DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT` to restore Hibernate's own default.
|
||||
See <<orm-hibernate-invalid-jdbc-access-error>> for related notes.
|
||||
|
||||
* Alternatively, consider obtaining the `EntityManagerFactory` from your application
|
||||
server itself (that is, through a JNDI lookup instead of a locally declared
|
||||
`LocalContainerEntityManagerFactoryBean`). A server-provided `EntityManagerFactory`
|
||||
might require special definitions in your server configuration (making the deployment
|
||||
less portable) but is set up for the server's JTA environment.
|
||||
|
||||
|
||||
[[orm-jpa-hibernate]]
|
||||
== Native Hibernate Setup and Native Hibernate Transactions for JPA Interaction
|
||||
|
||||
A native `LocalSessionFactoryBean` setup in combination with `HibernateTransactionManager`
|
||||
allows for interaction with `@PersistenceContext` and other JPA access code. A Hibernate
|
||||
`SessionFactory` natively implements JPA's `EntityManagerFactory` interface now
|
||||
and a Hibernate `Session` handle natively is a JPA `EntityManager`.
|
||||
Spring's JPA support facilities automatically detect native Hibernate sessions.
|
||||
|
||||
Such native Hibernate setup can, therefore, serve as a replacement for a standard JPA
|
||||
`LocalContainerEntityManagerFactoryBean` and `JpaTransactionManager` combination
|
||||
in many scenarios, allowing for interaction with `SessionFactory.getCurrentSession()`
|
||||
(and also `HibernateTemplate`) next to `@PersistenceContext EntityManager` within
|
||||
the same local transaction. Such a setup also provides stronger Hibernate integration
|
||||
and more configuration flexibility, because it is not constrained by JPA bootstrap contracts.
|
||||
|
||||
You do not need `HibernateJpaVendorAdapter` configuration in such a scenario,
|
||||
since Spring's native Hibernate setup provides even more features
|
||||
(for example, custom Hibernate Integrator setup, Hibernate 5.3 bean container integration,
|
||||
and stronger optimizations for read-only transactions). Last but not least, you can also
|
||||
express native Hibernate setup through `LocalSessionFactoryBuilder`,
|
||||
seamlessly integrating with `@Bean` style configuration (no `FactoryBean` involved).
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
`LocalSessionFactoryBean` and `LocalSessionFactoryBuilder` support background
|
||||
bootstrapping, just as the JPA `LocalContainerEntityManagerFactoryBean` does.
|
||||
See <<orm-jpa-setup-background, Background Bootstrapping>> for an introduction.
|
||||
|
||||
On `LocalSessionFactoryBean`, this is available through the `bootstrapExecutor`
|
||||
property. On the programmatic `LocalSessionFactoryBuilder`, an overloaded
|
||||
`buildSessionFactory` method takes a bootstrap executor argument.
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user