Mybatis深入:事务隔离级别和使用Spring事务管理

事务隔离级别:

  • 脏读:读取到了被回滚的数据,它毫无意义。
  • 虚读(不可重复读):由于其他事务更新数据,两次读取的数据不一致。
  • 幻读:由于其他事务执行插入删除操作,而又无法感知到表中记录条数发生变化,当下次再读取时会莫名其妙多出或缺失数据,就像产生幻觉一样。

(对于虚读和幻读的区分:虚读是某个数据前后读取不一致,幻读是整个表的记录数量前后读取不一致)

Mybatis深入:事务隔离级别和使用Spring事务管理_第1张图片

使用Spring事务管理

  • transactionManager:指定事务管理器
  • propagation:事务传播规则,一个事务可以包括N个子事务
  • isolation:事务隔离级别,不多说了
  • timeout:事务超时时间
  • readOnly:是否为只读事务,不同的数据库会根据只读属性进行优化,比如MySQL一旦声明事务为只读,那么久不允许增删改操作了。
  • rollbackFor和noRollbackFor:发生指定异常时回滚或是不回滚,默认发生任何异常都回滚

Spring默认的传播级别是PROPAGATION_REQUIRED,那么我们来看看,它是如何传播的,现在我们的Service类中一共存在两个事务,而一个事务方法包含了另一个事务方法:

@Transactional
public void test() {
    test2();
    if(true) throw new RuntimeException("我是测试异常!");  //发生异常时,会回滚另一个事务吗?
}

@Transactional
public void test2() {
    mapper.insertStudent();
}

最后我们得到结果,另一个事务被回滚了,也就是说,相当于另一个事务直接加入到此事务中了,也就是表中所描述的那样。

如果单独执行test2()则会开启一个新的事务,而执行test()则会直接让内部的test2()加入到当前事务中。

@Transactional
public void test() {
    test2();
}

@Transactional(propagation = Propagation.SUPPORTS)
public void test2() {
    mapper.insertStudent();
   	if(true) throw new RuntimeException("我是测试异常!");
}

现在我们将test2()的传播级别设定为SUPPORTS,那么这时如果单独调用test2()方法,并不会以事务的方式执行,当发生异常时,虽然依然存在AOP增强,但是不会进行回滚操作,而现在再调用test()方法,才会以事务的方式执行。

我们接着来看MANDATORY,它非常严格,如果当前方法并没有在任何事务中进行,会直接出现异常:

@Transactional
public void test() {
    test2();
}

@Transactional(propagation = Propagation.MANDATORY)
public void test2() {
    mapper.insertStudent();
    if(true) throw new RuntimeException("我是测试异常!");
}

NESTED级别表示如果存在外层事务,则此方法单独创建一个子事务,回滚只会影响到此子事务,实际上就是利用创建Savepoint,然后回滚到此保存点实现的。NEVER级别表示此方法不应该加入到任何事务中,其余类型适用于同时操作多数据源情况下的分布式事务管理,这里暂时不做介绍。 

 

 

你可能感兴趣的:(mybatis,mysql,数据库)