Spring的声明式事务管理可以通过两种方式来实现,一种是基于XML的方式,另一种是基于Annotation的方式。接下来的两个小节中,将对这两种声明式事务管理方式进行详细讲解。
基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。Spring 2.0以后,提供了tx命名空间来配置事务,tx命名空间下提供了元素来配置事务的通知(增强处理)。当使用元素配置了事务的增强处理后,就可以通过编写的AOP配置,让Spring自动对目标生成代理。
配置元素时,通常需要指定id和transaction-manager属性,其中id属性是配置文件中的唯一标识,transaction-manager属性用于指定事务管理器。除此之外,还需要配置一个子元素,该子元素可通过配置多个子元素来配置执行事务的细节。元素及其子元素如图5-2所示。
在图5-2中,配置元素的重点是配置子元素,图中使用灰色标注的几个属性是元素中的常用属性。
关于元素的属性描述如表5-2所示。
了解了如何在XML文件中配置事务后,接下来通过一个案例来演示如何通过XML方式来实现Spring的声明式事务管理。本案例以上一章的项目代码和数据表为基础,编写一个模拟银行转账的程序,要求在转账时通过Spring对事务进行控制,其具体实现步骤如下。
(1)在Eclipse中,创建一个名为chapter05的Web项目,在项目的lib目录中导入chapter04项目中的所有JAR包,并将AOP所需JAR包也导入到lib目录中。导入后的lib目录如图5-3所示。
(2)将chapter04项目中的代码和配置文件复制到chapter05项目的src目录下,并在AccountDao接口中,创建一个转账方法transfer(),其代码如下所示。
(3)在其实现类AccountDaoImpl中实现transfer()方法,编辑后的代码如下所示。
在上述代码中,使用了两个update()方法对account表中的数据执行收款和汇款的更新操作。在两个操作之间,添加了一行代码“int i = 1/0; ”来模拟系统运行时的突发性问题。如果没有事务控制,那么在转账操作执行后,收款用户的余额会增加,而汇款用户的余额会因为系统出现问题而不变,这显然是有问题的;如果增加了事务控制,那么在转账操作执行后,收款用户的余额和汇款用户的余额在问题出现前后都应该保持不变。
(4)修改配置文件applicationContext.xml,添加命名空间并编写事务管理的相关配置代码,如文件5-1所示。
在文件5-1中,首先启用了Spring配置文件的aop、tx和context 3个命名空间(从配置数据源到声明事务管理器的部分都没有变化),然后定义了id为transactionManager的事务管理器,接下来通过编写的通知来声明事务,最后通过声明AOP的方式让Spring自动生成代理。
(5)在com.itheima.jdbc包中,创建测试类TransactionTest,并在类中编写测试方法xmlTest(),如文件5-2所示。
在文件5-2中,获取了AccountDao实例后,调用了实例中的转账方法,由Jack向Rose的账户中转入100元。如果在配置文件中所声明的事务代码能够起作用,那么在整个转账方法执行完毕后,Jack和Rose的账户余额应该都是原来的数值。
在执行转账操作前,先查看account表中的数据,如图5-4所示。
从图5-4可以看出,此时Jack的账户余额是2000,而Rose的账户余额是500。执行完文件5-2中的测试方法后,Junit的控制台的显示结果如图5-5所示。
从图5-5可以看到,Junit控制台中报出了“/by zero”的算术异常信息。此时如果再次查询数据表account,会发现表中Jack和Rose的账户余额并没有发生任何变化(与图5-4中的显示结果一样),这说明Spring中的事务管理配置已经生效。