Spring 事务配置的几种方式及应用举例

本文分享了作者在项目中关于Spring事务管理的实践经验,包括代理工厂Bean事务管理、自动代理事务管理及零配置方式等,提供了详细的配置示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我以前在项目中的实践选择过程,最终选择第三种方案,几种都写出来与大家分享。 大家有其他好的方式,也欢迎分享。

环境:JDK 1.4.x , Hibernate 3.1, Spring 2.0.6, 开发模式: Service + DAO

1. 代理工厂Bean事务管理( *ProxyFactoryBean) + Service + DAO配置

我刚开始看Spring时用的书是林信良的《Spring技术手册》,书中对声明式事务主要采用 TransactionProxyFactoryBean,业务Bean如 Service或BO类继承它来进行事务控制。代理工厂Bean( *ProxyFactoryBean)这一类Spring提供的工厂类,可将一个 bean 进行委托代理,从而达到控制方法行为的目的。

此类事务配置一般如下(因为我们未采用这种方式,就以书上的JDBC datasource举例说明。不同公司采用的格式可能有所不同):
Xml代码 复制代码

1. <!-- 前面的 dataSource等配置略 ........ -->
2.
3. <!-- 事务管理器 -->
4. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
5. <property name="dataSource">
6. <ref local="dataSource" />
7. </property>
8. </bean>
9.
10. <!-- 事务模板 -->
11. <bean id="baseTransactionProxy"
12. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
13. abstract="true">
14. <property name="transactionManager" ref="transactionManager" />
15. <property name="transactionAttributes">
16. <props>
17. <prop key="*">PROPAGATION_REQUIRED</prop> <!-- 本文仅简单用一种方式说明。所有方法起事务,可以修改以精细和区别性控制事务 -->
18. </props>
19. </property>
20. </bean>
21.
22.
23. <!-- 业务对象 -->
24. <bean id="authService" parent="baseTransactionProxy">
25. <property name="target">
26. <bean class="com.xxxx.cms.service.AuthorityService">
27. <property name="authDao" ref="authDao" />
28. </bean>
29. </property>
30. </bean>
31. <bean id="departmentService" parent="baseTransactionProxy">
32. <property name="target">
33. <bean class="com.xxxx.cms.service.pojo.DepartmentService">
34. <property name="departmentDao" ref="departmentDao" />
35. </bean>
36. </property>
37. </bean>
38. <!-- 数据访问对象 -->
39. <bean id="authDao" class="com.xxxx.cms.dao.jdbc.AuthorityDao">
40. <property name="dataSource" ref="dataSource" />
41. </bean>
42. <bean id="departmentDao" class="com.xxxx.cms.dao.jdbc.DepartmentDao">
43. <property name="dataSource" ref="dataSource" />
44. </bean>

<!-- 前面的 dataSource等配置略 ........ -->
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<!-- 事务模板 -->
<bean id="baseTransactionProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop> <!-- 本文仅简单用一种方式说明。所有方法起事务,可以修改以精细和区别性控制事务 -->
</props>
</property>
</bean>
<!-- 业务对象 -->
<bean id="authService" parent="baseTransactionProxy">
<property name="target">
<bean class="com.xxxx.cms.service.AuthorityService">
<property name="authDao" ref="authDao" />
</bean>
</property>
</bean>
<bean id="departmentService" parent="baseTransactionProxy">
<property name="target">
<bean class="com.xxxx.cms.service.pojo.DepartmentService">
<property name="departmentDao" ref="departmentDao" />
</bean>
</property>
</bean>
<!-- 数据访问对象 -->
<bean id="authDao" class="com.xxxx.cms.dao.jdbc.AuthorityDao">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="departmentDao" class="com.xxxx.cms.dao.jdbc.DepartmentDao">
<property name="dataSource" ref="dataSource" />
</bean>


这种代理工厂Bean的事务管理一般都要求将 Service 的 bean 配置为 class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" , 上面的例子使用了 parent="baseTransactionProxy" 继承机制简化了原书中的配置。

代码中通过以下方式使用:



Java代码 复制代码

1. AuthService authService = (AuthService) context.getBean("authService");
2. boolean b = authService.hasPermission("TOKEN_XXXXX");

AuthService authService = (AuthService) context.getBean("authService");
boolean b = authService.hasPermission("TOKEN_XXXXX");



2. 自动代理事务(*AutoProxyCreator) + Service + DAO配置

*AutoProxyCreator这一类东东,能够自动为Spring容器中的bean进行 AOP 代理,配置起来能适当简化。一般需要用 BeanNameAutoProxyCreator 来配置对那些类进行自动代理, MethodPointcutAdvisor 来配置对哪些方法进行代理。

这种声明式事务配置采用拦截器(Interceptor)或通知器(Advisor) 进行事务控制,这里使用了Spring提供的 TransactionInterceptor 来管理事务。 (本质上 ProxyFactoryBean 也要生成被代理对象的字节码,不过每个类型的ProxyFactoryBean 只能固定处理一个 Aspect,不算真正的AOP)。

以下配置对 *Service 的所有方法进行事务控制。

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>



Xml代码 复制代码

1. <!-- 事务管理拦截器 -->
2. <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
3. <property name="transactionManager">
4. <ref local="transactionManager"/>
5. </property>
6. <property name="transactionAttributes">
7. <props>
8. <prop key="*">PROPAGATION_REQUIRED</prop> <!-- 本文仅简单用一种方式说明。所有方法起事务,还可以精细控制事务 -->
9. </props>
10. </property>
11. </bean>
12.
13. <!-- 配置要拦截哪些方法 -->
14. <bean id="trasactionMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
15. <property name="mappedNames">
16. <list>
17. <value>*</value> <!-- 所有方法 -->
18. </list>
19. </property>
20. <property name="advice">
21. <ref local="transactionInterceptor" />
22. </property>
23. </bean>
24.
25. <!-- 配置要拦截哪些类,并使用那些拦截器 -->
26. <bean id="ServiceAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
27. <property name="proxyTargetClass" value="true"></property>
28. <property name="beanNames">
29. <list>
30. <value>*Service</value>
31. </list>
32. </property>
33. <property name="interceptorNames">
34. <list>
35. <!-- 头三个是我们项目中用的其他 Advisor,这里展示了添加拦截器进行aspect控制的灵活性。省略他们的配置 -->
36. <value>monitorMethodPointcutAdvisor</value>
37. <value>asynmonitorMethodPointcutAdvisor</value>
38. <value>businessLogMethodPointcutAdvisor</value>
39. <value>trasactionMethodPointcutAdvisor</value> <!-- 事务拦截器, 直接配成 transactionInterceptor 去掉 trasactionMethodPointcutAdvisor bean 也可以, -->
40. </list>
41. </property>
42. </bean>

<!-- 事务管理拦截器 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop> <!-- 本文仅简单用一种方式说明。所有方法起事务,还可以精细控制事务 -->
</props>
</property>
</bean>
<!-- 配置要拦截哪些方法 -->
<bean id="trasactionMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>*</value> <!-- 所有方法 -->
</list>
</property>
<property name="advice">
<ref local="transactionInterceptor" />
</property>
</bean>
<!-- 配置要拦截哪些类,并使用那些拦截器 -->
<bean id="ServiceAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="proxyTargetClass" value="true"></property>
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<!-- 头三个是我们项目中用的其他 Advisor,这里展示了添加拦截器进行aspect控制的灵活性。省略他们的配置 -->
<value>monitorMethodPointcutAdvisor</value>
<value>asynmonitorMethodPointcutAdvisor</value>
<value>businessLogMethodPointcutAdvisor</value>
<value>trasactionMethodPointcutAdvisor</value> <!-- 事务拦截器, 直接配成 transactionInterceptor 去掉 trasactionMethodPointcutAdvisor bean 也可以, -->
</list>
</property>
</bean>


Service,DAO的配置方式稍微改变一下, Service不再作为ProxyFactoryBean的 target属性,而是一个顶级 bean,这样 Service bean看起来就更单纯一些。
Xml代码 复制代码

1. <!-- 业务对象 -->
2. <bean class="com.xxxx.cms.service.AuthorityService">
3. <property name="authDao" ref="authDao" />
4. </bean>
5. <bean class="com.xxxx.cms.service.pojo.DepartmentService">
6. <property name="departmentDao" ref="departmentDao" />
7. </bean>
8.
9. <!-- 数据访问对象 -->
10. <bean id="authDao" class="com.xxxx.cms.dao.jdbc.AuthorityDao">
11. <property name="dataSource" ref="dataSource" />
12. </bean>
13. <bean id="departmentDao" class="com.xxxx.cms.dao.jdbc.DepartmentDao">
14. <property name="dataSource" ref="dataSource" />
15. </bean>

<!-- 业务对象 -->
<bean class="com.xxxx.cms.service.AuthorityService">
<property name="authDao" ref="authDao" />
</bean>
<bean class="com.xxxx.cms.service.pojo.DepartmentService">
<property name="departmentDao" ref="departmentDao" />
</bean>
<!-- 数据访问对象 -->
<bean id="authDao" class="com.xxxx.cms.dao.jdbc.AuthorityDao">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="departmentDao" class="com.xxxx.cms.dao.jdbc.DepartmentDao">
<property name="dataSource" ref="dataSource" />
</bean>


代码中的使用方式不变,同 1 小节。

3. 自动代理 + Service DAO零配置

这种是我们项目中运用的方式,transactionInterceptor,trasactionMethodPointcutAdvisor ,ServiceAutoProxyCreator 三个 bean的配置不变。
Service,DAO 无需配置, 其原理参见我另一篇文章:

我的开发经验分享(一)-Spring业务bean零配置


代码中的使用方式不同,使用 ServiceFactory 直接创建bean,代码如下:



Java代码 复制代码

1. AuthService authService = (AuthService)ServiceFactory.createBean(AuthService.class);
2. boolean b = authService.hasPermission("TOKEN_XXXXX");

AuthService authService = (AuthService)ServiceFactory.createBean(AuthService.class);
boolean b = authService.hasPermission("TOKEN_XXXXX");


ServiceFactory 内部会自动注册未注册的 bean, 并和Spring 容器和已配置的拦截器关联。
 

4. Annotation 声明事务

如果是 JDK 1.5下,Spring 也支持 注释声明式事务,类似于如下代码(附部分片段):
Java代码 复制代码

1. @Transactional
2. public class PersonServiceImpl implements PersonService
3. { private EntityManager em;
4.
5. @PersistenceContext
6. public void setEntityManager(EntityManager em)
7. { this.em = em; }

@Transactional
public class PersonServiceImpl implements PersonService
{ private EntityManager em;
@PersistenceContext
public void setEntityManager(EntityManager em)
{ this.em = em; }


结合 <tx:annotation-driven/>配置。


它实际是将 xml 中的
Java代码 复制代码

1. <property name="transactionAttributes">
2. <props>
3. <prop key="*">PROPAGATION_REQUIRED</prop> <!-- 所有方法起事务,还可以精细控制事务 -->
4. </props>
5. </property>

<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop> <!-- 所有方法起事务,还可以精细控制事务 -->
</props>
</property>


转移到了Java代码中,本质上是一样的,两种方式都能进行精细事务管理。不过个人不太偏好这种方式,因为xml更便于集中管理,修改后无需编译。



1.5下Spring还用哪种更简化的事务管理方式,鄙人不是太熟,欢迎大家分享。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值