涉及知识点:没有事务管理的情况分析
1.对上一个没有事务管理的项目进行优化
目标是把类AlipayDaoImpl里的整个transfer()方法作为事务管理,这样transfer()里的所有操作都纳入同一个事务,从而使transfer()里的所有操作要么一起成功,要么一起失败。
2.优化流程
i.在applicationContext.xml中配置事务注解驱动
1 |
<!-- 开启事务注解驱动 --> <tx:annotation-driven transaction-manager="txManager" /> |
ii.在类或方法上使用@Transcational注解,即可实现事务管理,@Transcational注解若用在方法上,只能用在public方法上。
1 |
//注解事务 @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false) public void transfer(){} |
3.@Transcational注解有下面这些属性(可选)
propagation:用于设置事务传播的属性
isolation:用于设置事务1的隔离级别
readOnly:用于设置该方法对数据库的操作是否可读
timeout:用于设置本操作与数据库连接的超时时限
rollbackFor:用于指定需要回滚的异常类
rollbackForClassName:用于指定需要回滚的异常类的类名
noRollbackFor:用于指定不需要回滚的异常类
noRollbackForClassName:用于指定不需要回滚的异常类的类名
应用实例:模拟银行转账(添加事务管理),小黑,小白原本各有账户余额3000元,小黑转账1000元给小白,但转账过程中出现了异常
项目目录结构图
需要用到的数据库与数据表
1 |
create database aaa; use aaa; create table alipay( aliname varchar(60), amount double ); insert into alipay(aliname,amount) values ('小黑','3000'); insert into alipay(aliname,amount) values ('小白','3000'); select * from alipay; drop table alipay; |
数据表图
applicationContext.xml
1 |
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/aaa" /> <property name="username" value="root" /> <property name="password" value="123abc" /> </bean> <!-- 配置jdbcTemplate模板 注入dataSource --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" > <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置DAO,注入jdbcTemplate属性值 --> <bean id="alipayDao" class="com.xiaochen.dao.AlipayDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <!-- 定义事务管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启事务注解驱动 --> <tx:annotation-driven transaction-manager="txManager" /> </beans> |
IAlipayDao.java
1 |
package com.xiaochen.dao; public interface IAlipayDao { public void transfer(String fromA,String toB,int amount); } |
AlipayDaoImpl.java
1 |
package com.xiaochen.dao; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; public class AlipayDaoImpl implements IAlipayDao{ //定义jdbcTemplate类型的jdbcTemplate对象属性,但还并未实例化 //通过改属性可以更方便的操作数据库,无须再用以前JDBC的繁琐步骤 JdbcTemplate jdbcTemplate; public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override //注解事务 @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false) public void transfer(String fromA, String toB, int amount) { //执行转账操作:小黑将钱转出 String sql1="update alipay set amount=amount-? where aliname=?"; jdbcTemplate.update(sql1,amount,fromA); //模拟转账操作时发生异常 Integer.parseInt("a"); //执行转账操作:小白接收小黑转来的钱 String sql2="update alipay set amount=amount+? where aliname=?"; jdbcTemplate.update(sql2,amount,toB); } } |
Test.java
1 |
package com.xiaochen.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.xiaochen.dao.IAlipayDao; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); IAlipayDao alipayDao=(IAlipayDao)context.getBean("alipayDao"); alipayDao.transfer("小黑", "小白", 1000); } } |
运行结果图
转账前的数据库
转账后的数据库
测试时发现尽管转账中间发生了异常,但小黑与小白的钱并没有变化,保持了一致性,这样就达到了目的,证明了tranfer方法中的两个操作都纳入了同一个事务。发生异常时,事务回滚,保证了数据的一致性。