当使用 spring 的 AOP 为 web 应用提供事务管理服务时,我们需要指定事务策略,指定事务策略的格式如下:
1. 传播行为, 隔离层级, 只读, +异常, -异常
2. 传播行为必须设置,其他均可选择性地设置,中间以英文逗号分隔,例如:PROPAGATION_REQUIRED,readOnly,-BusinessException, 注意:在 BusinessException 前面加上 - 号表示发生指定异常时回滚操作,如果加上 + 号则表示发生指定异常时立即提交操作。
3. 如果你没有指定发生异常时事务该怎样进行,那么当真的在某个事务中发生很严重的异常时它不会回滚事务的。而这不是我们期望看到的,所以在这里应该指定你的应用异常(即业务逻辑异常)。
下面结合一个实例来总结一下指定事务策略时需要注意的问题。这个实例模拟一个 HR 系统中非常简单的一部分业务逻辑--新建一个员工信息的同时为其新建一个系统用户。
服务层的代码:
AnotherEmpService 类源码
1public class AnotherEmpService extends ServiceAdapter {
2
3
4
5 public void insert(Map map) throws Exception {
6 try {
7 Employee newEmp = (Employee)map.get("newEmp");
8 User newUser = (User)map.get("newUser");
9 // firstDAO 注入的是 EmployeeDAO 对象
10 firstDAO.insert(newEmp);
11 System.out.println(">>>>>>>>>>>>>>>>> is in AnotherEmpService");
12 // secondDAO 注入的是 UserDAO 对象
13 secondDAO.insert(newUser);
14 } catch(Exception e) {
15 System.out.println(">>>>>>>>>>>>>>>>>>>>>>Exception was catched in AnotherEmpService");
16 }
17 }
18}
EmployeeDAO 类中的 insert 方法可以正常执行成功,故该类的源代码省略。而在 UserDAO 类中我人为地扔出了一个 Exception 类型的异常,其源码如下:
UserDAO 类源码
1public class UserDAO extends DAOAdapter<User> {
2
3 public void insert(User po) throws Exception {
4
5 System.out.println(">>>>>>>>>> is in UserDAO!!!!");
6 po.setUserPwd("123456");
7 String sql = "insert into user (userName, userPwd, empID) values(?, ?, ?)";
8 Object[] args = {po.getUserName(), po.getUserPwd(), po.getEmpID()};
9 if(1 == 1) {
10 throw new Exception();
11 }
12 int[] argTypes = {Types.VARCHAR, Types.VARCHAR, Types.INTEGER};
13 this.jdbcTemplate.update(sql, args, argTypes);
14 }
15
16
17}
18
声明式事务的配置如下:
相关配置
1<bean id="transactionInterceptor"
2 class="org.springframework.transaction.interceptor.TransactionInterceptor">
3 <property name="transactionManager">
4 <ref bean="transactionManager" />
5 </property>
6 <property name="transactionAttributes">
7 <props>
8 <prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
9 <prop key="create*">PROPAGATION_REQUIRED,-Exception</prop>
10 <prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
11 <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
12 <prop key="*update*">PROPAGATION_REQUIRED,-Exception</prop>
13 <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
14 </props>
15 </property>
16 </bean>
17 <bean
18 class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
19 <property name="interceptorNames">
20 <list>
21 <value>transactionInterceptor</value>
22 </list>
23 </property>
24 <property name="beanNames">
25 <value>*Service</value>
26 </property>
27 </bean>
也就是说,我们准备在服务层进行事务控制,并希望将新建员工、新建用户这两个原子性的操作作为一个完整的事务执行。在这里有两个重要的因素影响着它们能否作为一个完整的事务而执行。下面我以一个表格的形式展示我的测试结果: