事务作用:在数据层保障一系列的数据库操作同成功同失败。
Spring事务:在数据层或业务层保障一系列的数据库操作同成功同失败。
//开启注解式事务驱动 @EnableTransactionManagement
模拟银行账户间转账业务
需求:实现两个账户间转账操作
需求微缩:A账户减钱,B账户加钱
分析:数据层提供基础操作,指定账户减钱(outMoney),指定用户加钱(inMoney)
业务层 提供转账操作(transfer),调用减钱操作与加钱操作
提供两个账号和操作金额执行转账操作
基于Spring整合Mybatis环境搭建是上述操作。
第一步:开始事务@EnableTransactionManagement
第二步:一般在业务层的接口上@Transactional
@Transactional public void transfer(String out,String in ,Double money) ;
第三步:JdbcConfig中配置事务
//配置事务管理器,mybatis使用的是jdbc事务 @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; }
PlatformTransactionManager是Spring提供的标准接口不能动,要动换下面的DataSourceTransactionManager()
Spring事务角色:
事务管理员:发起事务方,在Spring中通常只带业务层开启事务的方法。
事务协调员:加入事务方,在Spring中通常只带数据层方法,也可以是业务层方法。
上面这些属性都可以在 @Transactional 注解的参数上进行设置。
readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true。
timeout:设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超
时时间。
rollbackFor:当出现指定异常进行事务回滚
noRollbackFor:当出现指定异常不进行事务回滚
思考:出现异常事务会自动回滚,这个是我们之前就已经知道的
noRollbackFor是设定对于指定的异常不回滚,这个好理解
rollbackFor是指定回滚异常,对于异常事务不应该都回滚么,为什么还要指定?
这块需要更正一个知识点,并不是所有的异常都会回滚事务,比如下面的代码就不会回滚
出现这个问题的原因是,Spring的事务只会对 Error异常 和 RuntimeException异常 及
其子类进行事务回顾,其他的异常类型是不会回滚的,对应IOException不符合上述条
件所以不回滚
此时就可以使用rollbackFor属性来设置出现IOException异常不回滚
public interface AccountService {
/**
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
//配置当前接口方法具有事务
public void transfer(String out,String in ,Double money) throws
IOException;
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(String out,String in ,Double money) throws
IOException{
accountDao.outMoney(out,money);
//int i = 1/0; //这个异常事务会回滚
if(true){
throw new IOException(); //这个异常事务就不会回滚
}
accountDao.inMoney(in,money);
}
}
public interface AccountService {
/**
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
//配置当前接口方法具有事务
public void transfer(String out,String in ,Double money) throws
IOException;
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(String out,String in ,Double money) throws
IOException{
accountDao.outMoney(out,money);
//int i = 1/0; //这个异常事务会回滚
if(true){
throw new IOException(); //这个异常事务就不会回滚
}
accountDao.inMoney(in,money);
}
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional(rollbackFor = {IOException.class})
public void transfer(String out,String in ,Double money) throws
IOException{
accountDao.outMoney(out,money);
1
2
3
4
5
6
7
8
rollbackForClassName等同于rollbackFor,只不过属性为异常的类全名字符串
noRollbackForClassName等同于noRollbackFor,只不过属性为异常的类全名字符串
isolation设置事务的隔离级别
DEFAULT :默认隔离级别, 会采用数据库的隔离级别
READ_UNCOMMITTED : 读未提交
READ_COMMITTED : 读已提交
REPEATABLE_READ : 重复读取
SERIALIZABLE: 串行化
介绍完上述属性后,还有最后一个事务的传播行为,为了讲解该属性的设置,我们需要完成下面的案
例。
6.3.2 转账业务追加日志案例
6.3.2.1 需求分析
在前面的转案例的基础上添加新的需求,完成转账后记录日志。
需求:实现任意两个账户间转账操作,并对每次转账操作在数据库进行留痕
需求微缩:A账户减钱,B账户加钱,数据库记录日志
基于上述的业务需求,我们来分析下该如何实现:
①:基于转账操作案例添加日志模块,实现数据库中记录日志
②:业务层转账操作(transfer),调用减钱、加钱与记录日志功能
需要注意一点就是,我们这个案例的预期效果为:
无论转账操作是否成功,均进行转账操作的日志留痕
6.3.2.2 环境准备
该环境是基于转账环境来完成的,所以环境的准备可以参考 6.1.3的环境搭建步骤 ,在其基础上,我们
继续往下写
步骤1:创建日志表
//int i = 1/0; //这个异常事务会回滚
if(true){
throw new IOException(); //这个异常事务就不会回滚
}
accountDao.inMoney(in,money);
}
}