spring 事务部分共5篇文章
第一篇:spring中@EnableTransactionManager @Transactional注解实现机制
第二篇:spring boot中事务功能自动配置的加载过程分析
第三篇:spring@Transactional注解属性字段含义
第四篇:spring @Transactional如何测试事务注解生效
第五篇:spring及spring boot中事务相关知识的总结
本篇为第四篇
需求:在bo中要操作两张表,insert表1,根据insert的结果update表2。这是一个典型的spring事务的应用情形。在方法上使用@Transactional,如何进行测试,看事务是否起作用了呢?
解决方法:常用的测试方法是加入一条b=0;c=a/b;模拟出错的情况。测试应该包括insert表1的过程出错,以及update表2的过程出错。想到的另一种测试方法是修改表名,模拟出错的情况。
另外,在debug过程中发现,当执行了insert表1之后,还未执行update表2的时候,表1实际上并没有新增一条记录(这个要看查询线程处在什么隔离级别,如果处在read uncommitted下,那么其是能看到的,即发生“脏读”现象)。而在update表2执行完成之后,会在表1和表2同时新增或更新。
“默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。这点,Spring会在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中将底层连接的自动提交特性设置为false。”
那么问题来了,为什么autocommit设置为false就可以使用事务了呢?先把结论讲一下,就是在autocommit=off的情况下,可以将未commit的sql语句(其执行结果存储在缓存中的)回滚rollback掉。
当autocommit=on的情况下,是无法回滚的(注意:myisam引擎是无法使用事务的)
set names utf8;
create table t(a int, primary key (a))engine=innodb;
select @@autocommit;
set autocommit=off;
show variables like 'autocommit%';
insert into t(a)values(20);
insert into t(a)values(21);
insert into t(a)values(22);
rollback;
则执行的三条语句全部都会回滚掉。而如果
set names utf8;
create table t(a int, primary key (a))engine=innodb;
select @@autocommit;
set autocommit=off;
show variables like 'autocommit%';
insert into t(a)values(20);
commit;
insert into t(a)values(21);
insert into t(a)values(22);
rollback;
则执行的后两条语句会回滚掉
那么spring@Transactional来修饰一个方法时,将mysql的底层事务进行了抽象,总结起来就做了两件事:
1. 将autocommit=off,为回滚做准备
2. 在方法执行过程中如果报错,执行rollback,否则执行commit
再回到最初的那个问题,如何判断spring @Transactional是否成功了呢?
那么可以在第一条sql语句执行完成后打breakpoint,如果查询事务中在RC或RR级别下查不出,那么说明在执行事务;
而如果可以查出,说明autocommit仍为on的状态,没有在执行事务