代码准备
service层两个insert方法,insert1()和insert2(),insert2()插入两条数据,成功插入第一条后抛出异常
public void insert1(){
Actor actor=new Actor();
actor.setActorName("王五");
actorMapper.insertOrUpdate(actor);
}
public void insert2(){
Actor actor1=new Actor();
actor1.setActorName("张三");
Actor actor2=new Actor();
actor2.setActorName("李四");
int result1 = actorMapper.insertOrUpdate(actor1);
if(result1!=0){
throw new RuntimeException();
}
int result2 = actorMapper.insertOrUpdate(actor2);
}
controller层调用上述两个insert方法
@GetMapping("testInsert")
public void testInsert(){
actorService.insert1();
actorService.insert2();
}
- 在不加任何事物的情况加,insert2()方法在抛出异常后会停止执行,插入结果为王五和张三插入成功,李四插入失败
1、Propagation.REQUIRED:支持当前事务,如果不存在,就新建一个事务(spring默认的事务传播方式)
- 只在insert2()上加上注解
@Transactional(propagation = Propagation.REQUIRED) public void insert2(){。。。}
此时执行testInsert()后由于只有insert2()上有注解支持并且只支持当前事务,只有王五插入成功,insert2()中的插入回滚
- 只在testInsert()上加注解
@Transactional(propagation = Propagation.REQUIRED) public void testInsert(){。。。}
此时在testInsert()的事务中insert2()和insert1()都不存在事务,所以会创建事务,在insert2(0报错后,事务整体回滚,全部插入失败。
2、Propagation.SUPPORTS: 当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
- 只在insert2()上加入事务
@Transactional(propagation = Propagation.SUPPORTS) public void insert2(){。。。}
此时由于testInset()上没有事务,此时insert2()以非事务方式执行,此时李四无法插入,张三和王五插入成功
3、Propagation.MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
只在insert2()上加注解
@Transactional(propagation = Propagation.MANDATORY) public void insert2(){。。。}
此时只有王五插入成功,张三和李四插入失败的原因并不是事务回滚,而是insert2()方法没有执行,直接抛出的异常
4、REQUIRES_NEW:创建一个新事务,如果存在当前事务,则当前事务挂起
将异常抛出的位置改到testInsert()中去,去掉insert2()中的异常
public void insert1(){ Actor actor=new Actor(); actor.setActorName("王五"); actorMapper.insertOrUpdate(actor); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void insert2(){ Actor actor1=new Actor(); actor1.setActorName("张三"); Actor actor2=new Actor(); actor2.setActorName("李四"); int result1 = actorMapper.insertOrUpdate(actor1); int result2 = actorMapper.insertOrUpdate(actor2); }
@GetMapping("testInsert") @Transactional(propagation = Propagation.REQUIRED) public HttpResult testInsert(){ actorService.insert1(); actorService.insert2(); throw new RuntimeException(""); }
此时执行testInsert()方法,会发现王五插入失败,张三和李四插入成功,在insert2()上的注解 Propagation.REQUIRES_NEW在加入testInsert()时会重新创建一个单独的事务,而不受testInsert事务的影响,抛出异常导致insert1()回滚。
5、Propagation.NEVER:不使用事务,如果当前存在事务则报错抛出异常
@GetMapping("testInsert") @Transactional(propagation = Propagation.REQUIRED) public HttpResult testInsert(){ actorService.insert1(); actorService.insert2(); return HttpResult.ok(); } public void insert1(){ Actor actor=new Actor(); actor.setActorName("王五"); actorMapper.insertOrUpdate(actor); } @Transactional(propagation = Propagation.NEVER) public void insert2(){ Actor actor1=new Actor(); actor1.setActorName("张三"); Actor actor2=new Actor(); actor2.setActorName("李四"); int result1 = actorMapper.insertOrUpdate(actor1); int result2 = actorMapper.insertOrUpdate(actor2); }
此时全部插入失败,原因testInsert()上生命有事务,并且传播方式为REQUIRED,二insert2()上面的事务传播方式为不使用事务,此时insert2()抛出异常不执行方法,而testInsert()是在事务中,捕捉到insert2()的异常后进行回滚。所有插入都不成功。
6、Propagation.NOT_SUPPORTED:始终以非事务方式执行,如果当前存在事务,则挂起当前事务
与Propagation.NEVER的栗子相似,只把insert2()的事务注解改为@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void insert2(){。。。}
此时insert2()以非事务执行,张三插入成功,但是insert2()抛出异常,会使testInsert()发生回滚,insert1()发生回滚
7、Propagation.NESTED:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
和REQUIRES_NEW的区别
REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。
在NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务。和REQUIRED的区别
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否catch其异常,事务都会回滚
而在NESTED情况下,被调用方发生异常时,调用方可以catch其异常,这样只有子事务回滚,父事务不受影响带你读懂Spring 事务——事务的传播机制 - 知乎 (zhihu.com)
@GetMapping("testInsert") @Transactional(propagation = Propagation.REQUIRED) public HttpResult testInsert(){ actorService.insert1(); try { actorService.insert2(); } catch (Exception e) { e.printStackTrace(); } return HttpResult.ok(); } public void insert1(){ Actor actor=new Actor(); actor.setActorName("王五"); actorMapper.insertOrUpdate(actor); } @Transactional(propagation = Propagation.NESTED) public void insert2(){ Actor actor1=new Actor(); actor1.setActorName("张三"); Actor actor2=new Actor(); actor2.setActorName("李四"); int result1 = actorMapper.insertOrUpdate(actor1); if(result1==1){ throw new RuntimeException(); } int result2 = actorMapper.insertOrUpdate(actor2); }
在对insert2()进行异常捕获后,由于insert2上的注解会将其加入父事务,但是由于抛出异常,只有insert2()回滚。只有王五插入成功
若此时在testInsert()中抛出异常
@GetMapping("testInsert") @Transactional(propagation = Propagation.REQUIRED) public HttpResult testInsert(){ actorService.insert1(); try { actorService.insert2(); } catch (Exception e) { e.printStackTrace(); } throw new RuntimeException(); }
此时事务全部回滚,所有插入都失效,insert2()受到父事务的影响也发生回滚(不论在父事务中有没有捕获到insert2()的异常,insert2()都会发生回滚)