4.Spring事务角色
- Spring事务角色分为事务管理员和事务协调员。
- 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
- 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
- 结合入门案例分析
- 在入门案例中,没加@Transactional注解开启事务的情况下,减钱的outmoney方法、加钱的方法inmoney以及transfer接口都会各自开启一个事务,各自独立。当运行加钱事务出现异常的时候,减钱操作并不会加入加钱操作的事务回滚中,导致整个业务运行失败。
- 当只用@Transactional注解开启事务后,事务减钱事务TI与加钱事务T2都加入事务T,成为一个事务,这样当事务中的加钱事务部分出现问题时,整个事务回滚,程序终止运行,整体业务正常运行成功。
5.spring事务属性–rollbackfor
- 属性简介
属性 | 作用 | 示例 |
readonly | 设置是否为只读事务 | readOnly=true 只读事务 |
timeout | 设置事务超时时间 | timeout=-1(永不超时) |
rollbackfor | 设置事务回滚异常(class) | {NullPointException.class rollbackFor= |
rollbackForClassName | 设置事务回滚异常(string) | 同上格式为字符串 |
noRollbackFor | 设置事务不回滚异常(class) | noRollbackFor= (NullPointException.class} |
noRollbackForClassName | 设置事务不回滚异常(string) | 同上格式为字符串 |
propagation | 设置事务传播行为 | … |
- 添加事务属性格式举例
public interface AccountService { /** * 转账操作 * @param out 传出方 * @param in 转入方 * @param money 金额 */ //配置当前接口方法具有事务 @Transactional(readOnly = true,timeout = -1) public void transfer(String out,String in ,Double money) ; }
- rollbackfor属性介绍
- 在业务层实现类中抛出一个IOException异常
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void transfer(String out,String in ,Double money) throws IOException { accountDao.outMoney(out,money); //模拟抛出IOException异常 if(true){throw new IOException();} accountDao.inMoney(in,money); } }
- 运行模拟测试类
- 观察数据库表我们发现,开启事务后在遇到抛IOException类型的异常时,事务不会主动回滚,导致整体业务失败,这时候需要主动去配置。
public interface AccountService { /** * 转账操作 * @param out 传出方 * @param in 转入方 * @param money 金额 */ //配置当前接口方法具有事务 @Transactional(rollbackFor = {IOException.class}) public void transfer(String out,String in ,Double money) throws IOException; }
此时再次运行模拟测试类,当检测到IOExctpition类型的异常时,事务T回滚,数据库表中的数据不变。
- 开启Spring事务只回滚两种事务:ERROR系列(如内存溢出) 和 运行时异常(如NO Point Exception)。其余的均需要通过rollbackfor属性手动配置。
6.入门案例进阶–转账业务追加日志
- 案例需求及实现思路
- 编码环境准备
- 创建数据库表tbl_log
sql建表语句
use spring_db; drop table if exists tbl_log; create table tbl_log( id int primary key auto_increment, info varchar(100), createDate varchar(20) ); INSERT INTO tbl_log VALUES (1, '转账操作由Tom到Jerry,金额:100.0', '20:55:49');
表格示例
- LogDao数据层接口
public interface LogDao { @Insert("insert into tbl_log (info,createDate) values(#{info},now())") void log(String info); }
- LogService 业务层接口
public interface LogService { @Transactional void log(String out, String in, Double money); }
- LogService 业务层接口实现类
@Service public class LogServiceImpl implements LogService { @Autowired private LogDao logDao; public void log(String out,String in,Double money ) { logDao.log("转账操作由"+out+"到"+in+",金额:"+money); } }
- 将IOException相关的代码注释掉,保留最基础的Spring事务代码
- 文件结构示例
- 用try…finally结构编写业务层实现类AccountServiceImpl并运行测试类
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private LogService logService; public void transfer(String out,String in ,Double money) { try{ accountDao.outMoney(out,money); int i = 1/0; accountDao.inMoney(in,money); }finally { logService.log(out,in,money); } } }
- 将数据库中的金额分别手动修改重置到1000,并执行测试类
7. Spring事务属性–事务传播行为
- 探讨添加了异常后,日志能否正常加载
- 运行结果分析
此时再次运行测试类,我们可以发现数据库表中金额表数值由于开启了事务,当出现异常时,事务回滚,金额数值不变。同时日志表的数据也没有发生变化,不符合我们的预期。
- 存在的问题:
日志的记录与转账操作隶属同一个事务,同成功同失败
- 实现效果预期改进:
无论转账操作是否成功,日志必须保留,这时就需要通过事务传播行为来解决这个问题
- spring事务的7种传播行为
required | (默认传播行为),如果当前有事务,其他就用当前事务,不会新增事务。例如:方法A调用方法B,它们用同一个事务。(如果B没有事务,它们会用同一个事务。)(只要有一个回滚,整体就会回滚) |
requires_new | 如果当前有事务,其他不会加入当前事务,会新增事务。即他们的事务没有关系,不是同一个事务。如果其他没有事务,那么以当前事务运行。例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务) |
supports | 当前没有事务,就以非事务运行。当前有事务呢?就以当前事务运行。例如:方法A调用方法B,如果A没有事务,那么B就以非事务运行。如果A有事务就以A事务为准。如果A没有事务,那么B就会以非事务执行。 |
mandatory | 其他没有事务就会抛异常。当前没有事务抛出异常,当前有事务则支持当前事务。支持当前事务,如果当前没有事务就会抛出异常。例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。 |
not_supported | 以非事务执行。例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。 |
never | 以非事务执行,如果存在事务,抛出异常。总是以非事务执行,如果存在事务,那么就抛出异常。 |
nested | 如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与Required一样。例如:方法A中调用了方法B,B中try catch手动回滚,A不会回滚。 |
- 设置日志接口方法的事务传播行为属性
public interface LogService { @Transactional(propagation = Propagation.REQUIRES_NEW) void log(String out, String in, Double money); }
- 运行测试类观察效果
基于以上结果,Spring事务传播行为设置成功,业务功能运行正常。
`博客内容借鉴了bilibili黑马程序员SSM课程资料,如有侵权,请联系作者删除`
总结
欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。