赞
踩
基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。在使用XML文件配置声明式事务管理时,首先要引入tx命名空间,在引入tx命名空间之后,可以使用<tx:advice>元素来配置事务管理的通知,进而通过Spring AOP实现事务管理。
配置<tx:advice>元素时,通常需要指定 id 和 transaction-manager 属性,其中,id 属性是配置文件中的唯一标识,transaction-manager 属性用于指定事务管理器。除此之外,<tx:advice>元素还包含子元素<tx: attributes>,<tx:attributes>元素可配置多个<tx:method>子元素,<tx:method>子元素主要用于配置事务的属性。
属性 | 说明 |
name | 用于指定方法名的匹配模式,该属性为必选属性,它指定了与事务属性相关的方法名。 |
propagation | 用于指定事务的传播行为。 |
isolation | 用于指定事务的隔离级别。 |
read-only | 用于指定事务是否只读。 |
timeout | 用于指定事务超时时间。 |
rollback-for | 用于指定触发事务回滚的异常类。 |
no-rollback-for | 用于指定不触发事务回滚的异常类。 |
接下来通过一个案例演示如何通过XML方式实现Spring的声明式事务管理。本案例以9.2小节的项目代码和数据表为基础,编写一个模拟银行转账的程序,要求在转账时通过Spring对事务进行控制。案例具体实现步骤如下。
在chapter09项目的pom.xml文件中加入aspectjweaver依赖包和aopalliance依赖包作为实现切面所需的依赖包。
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.9.6</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>aopalliance</groupId>
- <artifactId>aopalliance</artifactId>
- <version>1.0</version>
- </dependency>
AccountDao接口中声明转账方法transfer()。
- // 转账
- public void transfer(String outUser,
- String inUser,
- Double money);
AccountDaoImpl实现类中实现AccountDao接口中的transfer()方法。
- // 转账 inUser:收款人; outUser:汇款人; money:收款金额
- public void transfer(String outUser, String inUser, Double money) {
- // 收款时,收款用户的余额=现有余额+所汇金额
- this.jdbcTemplate.update("update account set balance = balance +? "
- + "where username = ?",money, inUser);
- // 模拟系统运行时的突发性问题
- int i = 1/0;
- // 汇款时,汇款用户的余额=现有余额-所汇金额
- this.jdbcTemplate.update("update account set balance = balance-? "
- + "where username = ?",money, outUser);
- }
修改chapter09项目的配置文件applicationContext.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: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.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <!-- 1配置数据源 -->
- <bean id="dataSource" class=
- "org.springframework.jdbc.datasource.DriverManagerDataSource">
- <!--数据库驱动 -->
- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
- <!--连接数据库的url -->
- <property name="url" value="jdbc:mysql://localhost/spring?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai" />
- <!--连接数据库的用户名 -->
- <property name="username" value="root" />
- <!--连接数据库的密码 -->
- <property name="password" value="root" />
- </bean>
- <!-- 2配置JDBC模板 -->
- <bean id="jdbcTemplate"
- class="org.springframework.jdbc.core.JdbcTemplate">
- <!-- 默认必须使用数据源 -->
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!--定义id为accountDao的Bean-->
- <bean id="accountDao" class="com.itheima.AccountDaoImpl">
- <!-- 将jdbcTemplate注入到accountDao实例中 -->
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- <!-- 4.事务管理器,依赖于数据源 -->
- <bean id="transactionManager" class=
- "org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <!-- name:*表示任意方法名称 -->
- <tx:method name="*" propagation="REQUIRED"
- isolation="DEFAULT" read-only="false" />
- </tx:attributes>
- </tx:advice>
- <!-- 6.编写aop,让spring自动对目标生成代理,需要使用AspectJ的表达式 -->
- <aop:config>
- <!-- 切入点 -->
- <aop:pointcut expression="execution(* com.itheima.*.*(..))"
- id="txPointCut" />
- <!-- 切面:将切入点与通知整合 -->
- <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
- </aop:config>
- </beans>
创建测试类TransactionTest。
- public class TransactionTest {
- public static void main(String[] args) {
- ApplicationContext applicationContext =
- new ClassPathXmlApplicationContext("applicationContext.xml");
- // 获取AccountDao实例
- AccountDao accountDao =
- (AccountDao)applicationContext.getBean("accountDao");
- // 调用实例中的转账方法
- accountDao.transfer("lisi", "zhangsan", 100.0);
- // 输出提示信息
- System.out.println("转账成功!");}}
在执行转账操作前,也就是在执行第5不操作前,先查看account表中的数据。
- mysql> use spring
- Database changed
- mysql> select * from account;
- +----+----------+---------+
- | id | username | balance |
- +----+----------+---------+
- | 1 | zhangsan | 100 |
- | 3 | lisi | 500 |
- | 4 | wnagwu | 300 |
- +----+----------+---------+
- 3 rows in set (0.00 sec)
在执行第5步后,控制台中报出了“/by zero”的算术异常信息。此时再次查询数据表account。
- mysql> select * from account;
- +----+----------+---------+
- | id | username | balance |
- +----+----------+---------+
- | 1 | zhangsan | 100 |
- | 3 | lisi | 500 |
- | 4 | wnagwu | 300 |
- +----+----------+---------+
- 3 rows in set (0.00 sec)
未使用事物管理的缺陷
由XML方式实现声明式事务管理的案例可知,zhangsan的账户余额增加了100,而lisi的账户确没有任何变化,这样的情况显然是不合理的。这就是没有事务管理,系统无法保证数据的安全性与一致性,下面使用事务管理解决该问题。
在第4步的代码文件中添加事务管理的配置。
- <!-- 5.编写通知,需要编写对切入点和具体执行事务细节-->
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="*" propagation="REQUIRED"
- isolation="DEFAULT" read-only="false" /></tx:attributes>
- </tx:advice>
- <!-- 6.编写aop,使用AspectJ的表达式,让spring自动对目标生成代理-->
- <aop:config>
- <aop:pointcut expression="execution(* com.itheima.*.*(..))"
- id="txPointCut" />
- <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"
- </aop:config>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。