Spring声明式事务管理之三:配置方式+实例
1.Spring事务管理的五种配置方式
**Spring **的声明式事务管理底层实现是建立在 AOP 的基础之上。其本质是对方法执行前后进行拦截,然后在目标方法开始之前创建一个新事务或者加入一个已存在的事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理的最大优点就是不需要通过编程的方式管理事务,即不需要在系统的业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明,便可以将事务规则应用到业务逻辑中。
Spring配置文件中关于事务配置总是由三个部分组成,分别是DataSource
、TransactionManager
和代理机制,但是无论使用哪种配置方式,一般变化的只是代理机制。DataSource
、TransactionManager
这两部分只会随着数据访问方式的不同而有所变化,比如使用Hibernate
进行数据访问时,DataSource
实际为SessionFactory
,TransactionManager
的实现为HibernateTransactionManager
;使用JPA进行数据访问时,DataSource
实际为EntityManagerFactory
,TransactionManager
的实现为JpaTransactionManager
。
1.1 全注解方式
<context:annotation-config />
<context:component-scan base-package="com.feiyue" />
<!-- 定义sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
1.2 每个Bean使用一个代理
为每一个Bean Dao都配置一个代理,配置事务管理器及事务属性
<!-- 定义sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置DAO Target 实现 -->
<bean id="userDaoTarget" class="com.feiyue.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--配置userDao接口-->
<bean id="userDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userDaoTarget" />
<property name="proxyInterfaces" value="com.feiyue.dao.GeneratorDao" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
1.3 所有Bean共享一个代理基类
配置一个代理基类transactionBase,其他所有Bean Dao的配置都继承该基类
<!-- 定义sessionFactory-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--代理基类-->
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 配置userDaoTarget -->
<bean id="userDaoTarget" class="com.feiyue.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置userDao 继承代理基类-->
<bean id="userDao" parent="transactionBase" >
<property name="target" ref="userDaoTarget" />
</bean>
1.4 使用拦截器方式
定义拦截器transactionInterceptor,使用拦截器根据Bean的名字正则匹配*Dao自动创建代理
<!--定义sessionFactory-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--定义拦截器transactionInterceptor-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!--使用拦截器根据Bean的名字自动创建代理-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<!-- 配置DAO -->
<bean id="userDao" class="com.feiyue.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
1.5 使用Tx标签配置的拦截器
<context:annotation-config />
<context:component-scan base-package="com.feiyue" />
<!--定义sessionFactory-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--定义transactionManager-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!--aop切面-->
<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* com.feiyue.dao.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
2.Spring整合Mybatis声明式事务实例
2.1 事务配置文件
Spring4整合Mybatis并使用全注解方式配置事务管理,事务配置如下:
<!--mybatis 配置文件-->
<import resource="spring-mybatis.xml" />
<context:component-scan base-package="com.feiyue"/>
<!-- (事务管理)transaction manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" /></bean>
<!--全注解方式-->
<tx:annotation-driven transaction-manager="transactionManager" />
2.2 UserDao接口代码
UserDao中的接口定义在UserMapper.xml配置文件中实现
package com.feiyue.dao;
@Component
public interface UserDao extends FeiyueMapper<User>{
// 根据id查询User
public User findUserById(String id);
// 更新用户密码
public void updateUserPwd(String passwaor);
// 更新用户地址
public void updateUserAddress(String address);
}
2.3 UserService接口代码
package com.feiyue.service;
public interface UserService extends IService<User> {
// 根据id查询User
public User findUserById(String id);
// 更新用户密码
public void updateUserPwd(String password);
// 更新用户地址
public void updateUserAddress(String address);
//测试事务
public void testTranstion(String id,String password,String address);
}
2.4 UserServiceImpl实现代码
package com.feiyue.service.impl;
@Service("userService")
public class UserServiceImpl extends BaseService<User> implements UserService {
@Autowired
private UserDao userDao;
// 根据id查询User
public User findUserById(String id){
.........
}
// 更新用户密码
public void updateUserPwd(String password){
.........
}
// 更新用户地址
public void updateUserAddress(String address){
.........
}
/**
*测试事务
* 1.添加事务注解
* 使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时如何使用事务。
* 默认取值为REQUIRED,即使用调用方法的事务
* REQUIRES_NEW:使用自己的事务,调用的事务方法的事务被挂起。
* 2.使用isolation 指定事务的隔离级别,最常用的取值为READ_COMMITTED
* 3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚,
* 也可以通过对应的属性进行设置。通常情况下,默认值即可。
* 4.使用readOnly指定事务是否为只读。表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务。若真的是一个只读取数据库值的方法,应设置readOnly=true
* 5.使用timeout指定强制回滚之前事务可以占用的时间。
*/
@Transactional(propagation=Propagation.REQUIRED,
isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserException.class},
readOnly=false, timeout=3)
public void testTranstion(String id,String password,String address){
//查询
User user = this.findUserById(id);
//更新用户密码
this.updateUserPwd(password);
//更新用户地址
this.updateUserAddress(address);
}
}
Java技术日志本订阅号提供Java相关技术分享,从Java编程基础到Java高级技术,从JavaWeb技术基础Jsp、Servlet、>JDBC到SSH、SSM开发框架,从REST风格接口设计到分布式项目实战。剖析主流开源技术框架,用亲身
实践来谱写深度Java技术日志。
欢迎关注 Java技术日志 微信订阅号