事务的传播机制

一、事务的传播

事务的方法相互调用,事务在这些方法间传播。

二、spring事务传播类型

1. 用法:

@Transactional 使用枚举定义事务的传播类型

如,@Transactional(propagation=Propagation.REQUIRED)

注:Spring中默认采用AOP代理,同一个Service中调用,要采用注入的方式来调用,如果在使用this.方法名,
对象内部方法调用,不会通过spring代理,事务无效。

2. 7种类型:

1.REQUIRED --> 如果当前没有事务,则自己新建一个事务;如果当前存在事务,加入到testMain当前事务中
(示例一)预期:数据库数据没有变化,testMain声明了事务,testB执行时加入到当前事务中,testB回滚导致主方法也回滚。
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
  A(a1);  //调用A入参a1
  testB();    //调用testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
  B(b1);  //调用B入参b1
  throw Exception;     //发生异常抛出
  B(b2);  //调用B入参b2
}  
(示例二)预期:testMain当前没有事务,testB有声明事务且传播行为REQUIRED,自己新建事务,A表添加成功,B回滚
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
    B(b1);  //调用B入参b1
    throw Exception;     //发生异常抛出
    B(b2);  //调用B入参b2
}
2. SUPPORTS --> 当前存在事务,就加入到当前事务;如果当前没有事务,就以非事务方法运行
(示例)预期:testMain没有事务,所以默认testB也没有事务,a1,b1入库成功;如果testMain加入REQUIRED,当前存在事务,则加入当前事务中,a1,b1,b2入库均失败。
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
}

@Transactional(propagation = Propagation.SUPPORTS)
public void testB(){
    B(b1);  //调用B入参b1
    throw Exception;     //发生异常抛出
    B(b2);  //调用B入参b2
}
3. MANDATORY --> 当前存在事务,就加入当前事务;没有事务,就抛出异常。
(示例)预期:a1入库成功,testMain没有声明事务,抛出异常
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
}

@Transactional(propagation = Propagation.MANDATORY)
public void testB(){
    B(b1);  //调用B入参b1
    throw Exception;     //发生异常抛出
    B(b2);  //调用B入参b2
}
4. REQUIRES_NEW --> 创建一个新事物,当前存在事务,将事务挂起
(示例)预期:testMain抛出异常,testB开启新事务,不影响提交,b1,b2入库成功
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
    throw Exception;     //发生异常抛出
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testB(){
    B(b1);  //调用B入参b1
    B(b2);  //调用B入参b2
}
5. NOT_SUPPORTED --> 始终以非事务方法执行,如果当前存在事务,将事务挂起
(示例)预期:testB不使用事务,b1入库成功,然后抛出异常,testMain检测异常,回滚数据,a1入库失败
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testB(){
    B(b1);  //调用B入参b1
    throw Exception;     //发生异常抛出
    B(b2);  //调用B入参b2
}
6.NEVER 不使用事务,存在事务,抛出异常
(示例)预期:testB事务传播类型NEVER,testMain运行在事务中,testB不会执行抛出异常,testMain检测到异常,数据回滚,不会有数据入库
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
}

@Transactional(propagation = Propagation.NEVER)
public void testB(){
    B(b1);  //调用B入参b1
    B(b2);  //调用B入参b2
}
7.NESTED 如果当前事务存在,则在嵌套事务中执行,否则和REQUIRED一样
(示例)预期:和REQUIRES_NEW对比,REQUIRES_NEW是开启一个新事务,与原事务无关,NESTED子事务也会回滚,所有数据都不会入库
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
    A(a1);  //调用A入参a1
    testB();    //调用testB
    throw Exception;     //发生异常抛出
}
@Transactional(propagation = Propagation.NESTED)
public void testB(){
    B(b1);  //调用B入参b1
    B(b2);  //调用B入参b2
}
(示例)预期:和REQUIRED对比,使用子事务,仅testB方法回滚,a1,a2存储成功,catch子事务回滚了;如果是REQUIRED所有数据均回滚,就算在catch中,整个事务还是会回滚,因为调用方和被调用方公用的一个事务
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
    A(a1);  //调用A入参a1
    try{
        testB();    //调用testB
    }catch(Exception e){

    }
    A(a2);
}

@Transactional(propagation = Propagation.NESTED)
public void testB(){
    B(b1);  //调用B入参b1
    throw Exception;     //发生异常抛出
    B(b2);  //调用B入参b2
}

三、事务机制

1.脏读(Dirty Read)

在事务A执行的过程中,发生了更改(update),事务B读取了A未提交的数据;此刻,事务A因为某些原因发生回滚Rollback,事务B读取的数据就是脏数据。

2.不可重复读(Nonrepeatable Read)

事务B读取了2次数据,2次结果是不一样,在读取两次的过程中事务A发生了修改,导致读取出来的数据不一致,同一个事务中,读取两次的结果是不一样的就是不可重复读。

3.幻读

事务B前后两次读取同一个范围的数据,在事务B读取的过程中A增加了数据,导致B后一次读取查询中之前没有的行;
和不可重复读有些类似,幻读强调的是事务A增加的记录,不可重复读强调的是修改的数据。

4.第一类更新丢失

事务A和事务B都对数据进行更新,A发生异常,进行回滚,把B提交的事务覆盖了。

5.第二类更新丢失

事务A和事务B都对数据进行更新,事务A把事务B的更新数据的给覆盖了

四、事务隔离级别

主流的关系型数据库,事务的隔离级别从低到高:读为提交,读已提交,可重复读,串行化;隔离级别设定越高,越能保持数据的一致性,执行效率就越低,mysql默认是可重复读

读未提交:最低的事务隔离级别,只能解决第一类数据更新丢失

读已提交:可以防止脏读和第一类数据丢失

可重复读:一个事务多次读同一个数据,没有结束时,其他事务不能访问该数据,可能会出现幻读

串行化:事务一个一个执行,大量超时现象和锁竞争

在这里插入图片描述

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值