Spring Framework supports integration with the Java Persistence API (JPA) and supports native Hibernate for resource management, data access object (DAO) implementation, and transaction strategy. For example, Hibernate has first-class support with several handy IoC features that solve many common Hibernate integration problems. You can configure all supported functionality for OR (Object Relational) mapping tools using dependency injection. They can participate in Spring resource and transaction management, and they correspond to Spring's typed DAO transaction and exception hierarchies. The recommended integration style is to code DAOs instead of simple Hibernate or JPA APIs.

Spring brings significant functionality enhancements to your chosen ORM layer when building data access applications. You can use as many integration support tools as you want, and then weigh those integration efforts against the cost and risk of building a similar infrastructure in-house. You can use most ORM support just like libraries, regardless of technology, because everything is designed as a set of reusable JavaBeans. The ORM in the Spring IoC container makes it easy to configure and deploy. Thus, most of the examples in this section show the configuration inside a Spring container.

The advantages of using the Spring Framework to create ORM DAOs are:

  • Simplified testingSpring's IoC approach makes it easy to swap implementations and configurations of SessionFactory instances from Hibernate, DataSource instances from JDBC, transaction managers, and mapped object implementations ( if necessary). This, in turn, makes it much easier to test each piece of persistent code separately.

  • General data access exceptions. Spring can wrap exceptions from your ORM tool, transforming them from native (potentially checked) exceptions into a common DataAccessException hierarchy. This feature allows you to handle most non-recoverable persistent exceptions only at the appropriate levels, without annoying cliche catching, throwing, and declaring exceptions. But you can still catch and handle exceptions as needed. Remember that JDBC exceptions (including database-specific dialects) are also translated into the same hierarchy, which means that you can perform some JDBC operations within the consistent programming model.

  • Shared resource management Spring application contexts can handle the location and configuration of SessionFactory instances from Hibernate, EntityManagerFactory instances from JPA, DataSource instances from JDBC and other related resources. This makes it easier to manage and change these values. Spring offers efficient, simple, and secure handling of persistent storage resources. For example, dependent code that uses Hibernate typically needs to use the same Session from Hibernate to ensure efficiency and proper transaction processing. Spring makes it easy to create and bind a Session to the current thread in a transparent manner by exposing the current Session via a SessionFactory from Hibernate. Thus, Spring solves many of the chronic problems of typical Hibernate use for any local or transactional JTA environment.

  • Integrated transaction management. You can wrap ORM code a declarative method interceptor based on aspect-oriented programming (AOP), either by using the @Transactional annotation or by explicitly configuring AOP-Advice for transactions in an XML configuration file. In both cases, transaction semantics and exception handling (rollback, etc.) are done for you. As described in the "Resource and Transaction Management" section , you can also change various transaction managers without affecting ORM related code. For example, you can switch between local transactions and JTA, with the same rich services (such as declarative transactions) available in both scenarios. In addition, code associated with JDBC can be fully transactionally integrated with code used for ORM. This is useful for data access that is not suitable for ORM (such as batch processing and BLOB streaming), but still needs to share common transactions with ORM operations.

For more comprehensive ORM support, including support for alternative database technologies such as MongoDB, it is worth taking a look at the Spring Data. If you are a JPA user, "Getting started with data access with JPA" from https://spring.io would be a great introduction.

General approaches to ORM integration

This section discusses recommendations that apply to all ORM technologies. The section on Hibernate provides more details and also demonstrates these features and configurations in context.

The main goal of ORM integration in Spring is clear application composition (across any data access and transaction technology) and free binding of application objects - no more business service dependencies on data access or transaction strategy, no hard-coded lookup resources, no hard-to-replace single objects, and no custom service registries. The goal is to provide one simple, consistent approach to discovering and binding application objects while making them as reusable as possible and free from container dependencies. All of the individual data access functions can be used separately, but they also play nicely with Spring's concept of application context, providing XML-based configuration and cross-referencing to regular JavaBean instances that don't necessarily need to be Spring compatible. In a typical Spring application, many important objects are JavaBeans: data access patterns, data access objects, transaction managers, business services using data access objects and transaction managers, web view resolvers, web controllers using business services, and so on.

Resource and Transaction Management

Typical business applications have a lot of repetitive code to manage resources. Many projects try to come up with their own solutions, sometimes sacrificing proper troubleshooting for the sake of programming convenience. Spring advocates simple solutions for proper resource handling, namely IoC through templating in the case of JDBC and the use of AOP interceptors for ORM technologies.

The framework ensures proper resource handling and appropriate translation of API-specific exceptions into an unchecked hierarchy infrastructure exceptions. Spring introduces a DAO exception hierarchy applicable to any data access strategy. In the case of straight JDBC, the JdbcTemplate class mentioned in previous section handles connections and proper translation of SQLException into the DataAccessException hierarchy, including translation of database-specific SQL error codes into meaningful exception classes. For ORM technologies, see next section on how to take advantage of the same benefits of exception conversion.

When it comes to transaction management, the JdbcTemplate class connects to Spring's transaction support and supports JTA and JDBC transactions through their respective Spring transaction managers. In terms of supported ORM technologies, Spring offers support for Hibernate and JPA through the Hibernate and JPA transaction managers, as well as JTA support. For more information about transaction support, see the chapter "Transaction Management".

Converting Exceptions

If Hibernate or JPA are used in a DAO, then you need to decide how to handle the native exception classes of persistent storage technology. DAO throws a subclass of HibernateException or PersistenceException depending on the technology. All of these exceptions are run-time exceptions and should not be declared or caught. You may also have to deal with IllegalArgumentException and IllegalStateException. This means that callers can only handle exceptions that are considered critical if they want to avoid depending on the persistence technology's own exception structure. It is impossible to determine specific causes (such as optimistic lock failure) without linking the calling program to the implementation strategy. This trade-off may be acceptable for applications that are heavily ORM based or do not need special exception handling (or both). However, Spring allows exception translation to be applied transparently through the @Repository annotation. The following examples (one for Java configuration and one for XML configuration) show how to do this:

Java
@Repository
public class ProductDaoImpl implements ProductDao {
    // class body here... }
Kotlin
@Repository
class ProductDaoImpl : ProductDao {
    // class body here...}
<beans>
    <!-- Bean conversion postprocessor exception... -->
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    <bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>

The post-processor automatically searches for all exception transformers (implementations of the PersistenceExceptionTranslator interface) and supplies all beans with Advice marked with the @Repository annotation so that detected resolvers can catch and apply the appropriate conversion to the thrown exceptions.

In general, it is possible to implement a DAO based on the API and annotations of conventional persistent storage support technology , while taking advantage of Spring-managed transactions, dependency injection, and transparent exception translation (if desired) into custom Spring exception hierarchies.