我们大都选择使用声明式(XML 或者注解)来配置事务,因为这种方式对代码的侵入最小。特别是 XML 方式的配置,可以让事务管理配置信息从业务代码中完全移除。
Spring 的声明式事务管理是通过 AOP 实现的。 Spring 会读取事务的声明配置,将事务管理的增强逻辑,动态织入到业务方法的相应连接点中 。
Spring 2.0 之后引入了 AspectJ 切面定义语言,所以我们可以基于 aop/tx 命名空间来配置事务。
假设有这样的一个 UserService 类:
@Service
public class UserService {
@Autowired
private UserDao userDao;
/**
* 新增
*
* @param user
*/
public int addUser(final User user) {
return userDao.save(user);
}
/**
* 依据 Id,获取账号
*
* @param userId
* @return
*/
public User getUser(Long userId) {
return userDao.get(userId);
}
/**
* 更新账号所对应的密码
* @param userId
* @param pwd
*/
public int update(Long userId, String pwd) {
return userDao.update(userId, pwd);
}
}
希望让 get***() 方法拥有只读事务,其它方法拥有写事务。对这一业务要求,我们可以使用 aop/tx 命名空间来配置。
spring_tx.xml:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
">
<!-- 扫描包含注解定义的类包-->
<context:component-scan base-package="net.deniro.xxx.transaction.xml"/>
<!-- 数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/spring4"
p:username="root"
p:password="xxx"/>
<!-- JDBC 模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"
/>
<!-- 事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 增强事务-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="false"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="update"/>
</tx:attributes>
</tx:advice>
<!-- 定义需要增强的目标方法-->
<aop:config>
<!-- 增强切面-->
<aop:pointcut id="serviceMethod" expression="exec。ution(* net.deniro.xxx.transaction.xml.UserService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
</beans>
在 aop 命名空间中,通过切点表达式,将 net.deniro.xxx.transaction.xml.UserService 中的所有方法,都纳入了事务增强的管理范围。
其中,最关键的是 <tx:method>
元素,它拥有如下属性:
属性 | 是否必须 | 默认值 | 说明 |
---|---|---|---|
name | 必须 | 相关联的方法名。可以使用通配符(*)。 | 形如:get*、add* 等。 |
propagation | - | REQUIRED | 事务传播行为,可选值为:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED |
isolation | - | DEFAULT | 事务隔离级别,可选值为:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE |
timeout | - | -1 | 事务超时时间(单位为 s)。如果为 -1,则事务的超时时间由底层事务系统决定。 |
read-only | - | false | 是否只读 |
rollback-for | - | 所有运行期异常,都回滚 | 触发事务回滚的 Excepiton 名称,多个以逗号隔开。 |
norollback-for | 所有检查型异常,都不回滚 | 不触发事务回滚的 Excepiton 名称,多个以逗号隔开。 |
基于 aop/tx 来配置声明式事务管理,是实际项目中最常使用的配置方式,因为它的表达能力最强而且使用也最为灵活 。