如何在Spring 5与Hibernate 5应用中整合Spring JPA并配置相关组件
Hey there! Let's walk through how to set up Spring JPA and Hibernate 5 side by side in your Spring 5 application, covering transaction managers, entity managers, Hibernate Sessions, and how to use all of this in your code—all configured via applicationContext.xml.
1. First: Set Up Your Data Source
You can't do much without a database connection. Let's configure a basic data source (I'll use Apache Commons DBCP here, but you can swap in HikariCP or another implementation if preferred):
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC"/> <property name="username" value="db_user"/> <property name="password" value="db_password"/> <property name="initialSize" value="5"/> <property name="maxTotal" value="20"/> </bean>
2. Configure the EntityManagerFactory (Spring JPA's Core)
Spring JPA relies on EntityManagerFactory to manage entity managers, and since Hibernate is our JPA provider, we'll use LocalContainerEntityManagerFactoryBean to wire everything up. This bean automatically creates a Hibernate SessionFactory under the hood, so you get both JPA and Hibernate support in one setup:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!-- Wire up our data source --> <property name="dataSource" ref="dataSource"/> <!-- Tell Spring where to scan for your JPA entity classes --> <property name="packagesToScan" value="com.yourpackage.entities"/> <!-- Specify Hibernate as the JPA vendor --> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <!-- Add Hibernate-specific configuration properties --> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <!-- Adjust to create/create-drop/validate as needed --> </props> </property> </bean>
3. Transaction Managers: JPA + Hibernate
Here's a key insight: JpaTransactionManager works seamlessly with Hibernate because Hibernate is a JPA implementation. This manager handles transactions for both JPA EntityManager and Hibernate Session operations. If you have legacy code that relies on a dedicated Hibernate transaction manager, you can configure both—though the JPA manager is sufficient for most modern use cases.
Option 1: Primary JPA Transaction Manager (Recommended)
This is the default setup you'll want for most applications:
<!-- JPA Transaction Manager --> <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Enable annotation-driven transaction management --> <tx:annotation-driven transaction-manager="jpaTransactionManager"/>
Option 2: Add Hibernate Transaction Manager (If Needed)
If you have code that uses Hibernate's native API exclusively, add this alongside the JPA manager:
<!-- Hibernate Transaction Manager --> <bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" value="#{entityManagerFactory.unwrap(org.hibernate.SessionFactory.class)}"/> </bean>
When using this, specify the manager in your @Transactional annotation like: @Transactional("hibernateTransactionManager").
4. Expose Hibernate SessionFactory & Session
If you want to use Hibernate's Session directly (instead of JPA's EntityManager), you can expose the auto-created SessionFactory as a bean, or even a thread-bound Session:
<!-- Expose Hibernate SessionFactory (extracted from EntityManagerFactory) --> <bean id="sessionFactory" factory-bean="entityManagerFactory" factory-method="unwrap"> <constructor-arg value="org.hibernate.SessionFactory"/> </bean> <!-- Optional: Expose a thread-bound current Hibernate Session --> <bean id="currentSession" factory-bean="sessionFactory" factory-method="getCurrentSession"/>
5. Using These Beans in Your Application
Injecting EntityManager (Spring JPA)
Use @PersistenceContext to inject the JPA EntityManager into your DAOs or services:
import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.stereotype.Repository; @Repository public class UserDao { @PersistenceContext private EntityManager entityManager; public User findById(Long id) { return entityManager.find(User.class, id); } public void saveUser(User user) { entityManager.persist(user); } }
Using Hibernate Session
Inject the SessionFactory to get the current thread-bound session, or inject the currentSession bean directly:
import org.hibernate.Session; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @Repository public class UserHibernateDao { @Autowired private Session currentSession; public User findById(Long id) { return currentSession.get(User.class, id); } // Alternatively, inject SessionFactory: // @Autowired // private SessionFactory sessionFactory; // public User findById(Long id) { // return sessionFactory.getCurrentSession().get(User.class, id); // } }
Managing Transactions
Add the @Transactional annotation to your service methods to handle transactions automatically. It uses the default manager we configured, or specify a custom one if needed:
import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserService { @Autowired private UserDao userDao; @Transactional // Uses jpaTransactionManager by default public User createUser(User user) { userDao.saveUser(user); return user; } // If using the Hibernate transaction manager: // @Transactional("hibernateTransactionManager") // public User updateUser(User user) { // currentSession.merge(user); // return user; // } }
Full Example of applicationContext.xml
Putting it all together, here's a complete configuration snippet:
<?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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Scan for @Service, @Repository, etc. --> <context:component-scan base-package="com.yourpackage"/> <!-- Data Source --> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC"/> <property name="username" value="db_user"/> <property name="password" value="db_password"/> </bean> <!-- EntityManagerFactory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com.yourpackage.entities"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- JPA Transaction Manager --> <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Optional: Hibernate Transaction Manager --> <bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" value="#{entityManagerFactory.unwrap(org.hibernate.SessionFactory.class)}"/> </bean> <!-- Expose Hibernate SessionFactory --> <bean id="sessionFactory" factory-bean="entityManagerFactory" factory-method="unwrap"> <constructor-arg value="org.hibernate.SessionFactory"/> </bean> <!-- Enable Annotation-Driven Transactions --> <tx:annotation-driven transaction-manager="jpaTransactionManager"/> </beans>
内容的提问来源于stack exchange,提问作者Kingamere

