Spring Framework 整合 Hibernate 的全面指南
前言
在现代企业应用开发中,对象关系映射(ORM)技术扮演着重要角色。Spring Framework 提供了对多种 ORM 技术的支持,其中 Hibernate 是最受欢迎的选择之一。本文将深入探讨 Spring 如何优雅地集成 Hibernate,帮助开发者构建高效、可维护的数据访问层。
Hibernate 版本支持说明
Spring Framework 6.0 对 Hibernate 的支持有以下要点:
- 对于
HibernateJpaVendorAdapter
和原生 HibernateSessionFactory
配置,需要 Hibernate ORM 5.5+ - 推荐使用 Hibernate ORM 5.6 作为该代系的最后一个功能分支
- Hibernate ORM 6.x 仅支持作为 JPA 提供者(
HibernateJpaVendorAdapter
) - 新项目推荐使用 Hibernate ORM 6.1/6.2 配合 JPA 风格配置
配置 SessionFactory
基础配置
在 Spring 容器中配置 SessionFactory
是集成 Hibernate 的第一步。通过将资源(如 JDBC DataSource
或 Hibernate SessionFactory
)定义为 Spring bean,可以避免硬编码资源查找。
<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>
<!-- 配置SessionFactory -->
<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>
JNDI 数据源配置
如果需要使用 JNDI 数据源(通常由应用服务器管理),配置非常简单:
<beans>
<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>
</beans>
高级特性
Spring 还提供了 LocalSessionFactoryBuilder
,可以与 @Bean
风格的配置无缝集成。LocalSessionFactoryBean
和 LocalSessionFactoryBuilder
都支持后台引导,Hibernate 初始化可以在给定的引导执行器上与应用程序引导线程并行运行。
基于原生 Hibernate API 实现 DAO
基本实现
Hibernate 的上下文会话功能允许 Hibernate 自己管理每个事务的当前 Session
。这与 Spring 的每个事务同步一个 Hibernate Session
的方式类似。以下是一个基于原生 Hibernate API 的 DAO 实现示例:
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();
}
}
配置 DAO
在 Spring 容器中配置这个 DAO:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
</beans>
这种 DAO 风格的优点是它只依赖于 Hibernate API,不需要导入任何 Spring 类。对于 Hibernate 开发者来说,这感觉更自然。
声明式事务管理
使用 @Transactional 注解
Spring 的声明式事务支持允许你用 AOP 事务拦截器替换 Java 代码中的显式事务划分 API 调用。你可以使用 Java 注解或 XML 在 Spring 容器中配置这个事务拦截器。
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();
}
}
容器配置
在容器中,你需要设置 PlatformTransactionManager
实现(作为 bean)和一个 <tx:annotation-driven/>
条目,以在运行时启用 @Transactional
处理。
<?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 等配置 -->
<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>
编程式事务管理
实现方式
你可以在应用程序的更高层次划分事务,覆盖任意数量操作的底层数据访问服务。以下是一个编程式事务管理的示例:
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);
// 执行价格增加操作...
}
});
}
}
容器配置
<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>
事务管理策略
事务管理器选择
TransactionTemplate
和 TransactionInterceptor
都将实际的事务处理委托给 PlatformTransactionManager
实例。对于 Hibernate 应用,可以是:
HibernateTransactionManager
(用于单个 HibernateSessionFactory
,在底层使用ThreadLocal
Session
)JtaTransactionManager
(委托给容器的 JTA 子系统)
你甚至可以自定义 PlatformTransactionManager
实现。
分布式事务
对于跨多个 Hibernate 会话工厂的分布式事务,你可以将 JtaTransactionManager
作为事务策略与多个 LocalSessionFactoryBean
定义结合使用。如果所有底层 JDBC 数据源都是事务性容器数据源,业务服务可以跨任意数量的 DAO 和会话工厂划分事务,只要它使用 JtaTransactionManager
作为策略。
缓存处理
HibernateTransactionManager
和 JtaTransactionManager
都允许使用 Hibernate 进行适当的 JVM 级缓存处理,而无需容器特定的事务管理器查找或 JCA 连接器(如果不使用 EJB 启动事务)。
容器管理与本地定义资源的比较
在容器管理的 JNDI SessionFactory
和本地定义的 SessionFactory
之间切换不需要更改任何应用程序代码。Spring 的事务支持不依赖于容器。当配置了除 JTA 之外的任何策略时,事务支持也可以在独立或测试环境中工作。特别是在典型的单数据库事务情况下,Spring 的单资源本地事务支持是 JTA 的轻量级且强大的替代方案。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考