
5.3 声明式事务管理
Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明便可以将事务规则应用到业务逻辑中。通常情况下,在开发中使用声明式事务处理不仅因为其简单,更主要的是因为这样使得纯业务代码不被污染,极大地方便了后期的代码维护。
与编程式事务管理相比,声明式事务管理唯一不足的地方是最细粒度只能作用到方法级别,无法做到像编程式事务管理那样可以作用到代码块级别。但即便有这样的需求,也可以通过变通的方法进行解决,例如可以将需要进行事务处理的代码块独立为方法等。
Spring的声明式事务管理可以通过两种方式来实现,一是基于XML的方式,二是基于@Transactionall注解的方式。
5.3.1 基于XML方式的声明式事务管理
基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。Spring框架提供了tx命名空间来配置事务,提供了<tx:advice>元素来配置事务的通知。在配置<tx:advice>元素时一般需要指定id和transaction-manager属性,其中id属性是配置文件中的唯一标识,transaction-manager属性指定事务管理器。另外还需要<tx:attributes>子元素,该子元素可配置多个<tx:method>子元素指定执行事务的细节。
在<tx:advice>元素配置了事务的增强处理后就可以通过编写AOP配置让Spring自动对目标对象生成代理。下面通过一个实例演示如何通过XML方式来实现Spring的声明式事务管理。为体现事务管理的流程,本实例创建了Dao、Service和Controller 3层,具体实现步骤如下:
① 导入相关的JAR包
在ch5应用的基础上导入AOP所需要的JAR,导入后的lib目录如图5.5所示。

图5.5 ch5应用所需要的JAR包
② 创建Dao层
在ch5的src目录下创建com.statement.dao包,并在该包中创建TestDao接口和TestDaoImpl实现类。数据访问层有两个数据操作方法,即save和delete方法。
TestDao接口的代码如下:

TestDaoImpl实现类的代码如下:

③ 创建Service层
在ch5的src目录下创建com.statement.service包,并在该包中创建TestService接口和TestServiceImpl实现类。在Service层依赖注入数据访问层。
TestService接口的代码如下:

TestServiceImpl实现类的代码如下:

④ 创建Controller层
在ch5的src目录下创建com.statement.controller包,并在该包中创建StatementController控制器类。在控制层依赖注入Service层。
StatementController类的代码如下:

⑤ 创建配置文件
在ch5的src目录下创建com.statement.xmll包,并在该包中创建配置文件XMLstatementapplicationContext.xml。在配置文件中使用<tx:advice>编写通知声明事务,使用<aop:config>编写AOP让Spring自动对目标对象生成代理。
XMLstatementapplicationContext.xml文件的代码如下:

⑥ 创建测试类
在ch5的src目录下创建com.statement.test包,并在该包中创建测试类XMLTest,在测试类中通过访问Controller测试基于XML方式的声明式事务管理。
测试类XMLTest的代码如下:

测试类XMLTest的运行结果与图5.4一样,这里不再赘述。
5.3.2 基于@Transactional注解的声明式事务管理
@Transactional注解可以作用于接口、接口方法、类以及类的方法上。当作用于类上时,该类的所有public方法都将具有该类型的事务属性,同时也可以在方法级别使用该注解来覆盖类级别的定义。虽然@Transactional注解可以作用于接口、接口方法、类以及类的方法上,但是Spring小组建议不要在接口或者接口方法上使用该注解,因为它只有在使用基于接口的代理时才会生效。
如果不想对某个异常进行事务处理,可以使用如下代码:

下面通过实例演示使用@Transactional注解进行事务管理的过程,该实例的Dao、Service和Controller层与5.3.1节中的相同,具体步骤如下:
① 创建配置文件
在com.statement.xml包中创建配置文件annotationstatementapplicationContext.xml,在配置文件中使用<tx:annotation-driven>元素为事务管理器注册注解驱动器。
annotationstatementapplicationContext.xml文件的代码如下:

② 为Service层添加@Transactional注解
在Spring MVC(后续章节讲解)中通常通过Service层进行事务管理,因此需要为Service层添加@Transactional注解。
添加@Transactional注解后的TestServiceImpl类的代码如下:

测试类的运行结果与5.3.1节一样,这里不再赘述。