一.了解spring事务的传播机制
传播机制的定义
REQUIRED 如果当前没有事务,则自己新建一个事;如果当前存在事务,则加入这个事务
REQUIRES_NEW 如果当前没有事务,创建一个新事务;如果存在事务,则挂起该事务,并且新建事务
SUPPORTS 如果当前没有事务,就以非事务方法执行 ;当前存在事务,则加入当前事务,
MANDATORY 如果当前没有事务,则抛出异常;当前存在事务,则加入当前事务
NOT_SUPPORTED 始终以非事务方式执行,如果当前存在事务,则挂起当前事务
NEVER 不使用事务,如果当前事务存在,则抛出异常
NESTED 如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
NESTED和REQUIRES_NEW的区别: REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在NESTED情况下父事务回滚时,子事务也会回滚,
而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务。
NESTED和REQUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否catch其异常,事务都会回滚而在NESTED情况下,被调用方发生异常时,调用方可以catch其异常,这样只有子事务回滚,父事务不受影响
传播机制的介绍
如果能理解上面关于事务传播的定义,下面的内容可以跳过,接下来我带你们了解一下事务的传播机制
上伪代码喽
public void insertA(Data data){
//向表a插入数据
}
public void insertB(Data data){
//更新表b的数据
}
REQUIRED
1.如果当前已经存在事务,加入这个事务
当前情形仍然适用于SUPPORTS,MANDATORY
@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRED )
public void test(){
insertA(a);
try{
testB();
}catch(Exception e){
}
}
//@Transactional(rollbackFor = Exception.class,propagation= Propagation.MANDATORY )
//@Transactional(rollbackFor = Exception.class,propagation= Propagation.SUPPORTS )
@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRED )
public void testB(){
insertB(b);
throw new NullPointerException();
insertB(c);
}
数据a,b, c都属于一个事务, 要么全部回滚(数据库保持原样),要么全部提交(a,b入库)
DataSourceTransactionManager platformTransactionManager = new DataSourceTransactionManager();
//GlobalRollbackOnParticipationFailure如果为false 部分失败不回滚
//GlobalRollbackOnParticipationFailure如果为false 部分失败回滚
platformTransactionManager.setGlobalRollbackOnParticipationFailure(false);
2.如果当前不存在事务,新建事务
当前情形仍然适用于 REQUIRES_NEW,NESTED
public void test(){
insertA(a);
try{
testB();
}catch(Exception e){
}
}
//@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRES_NEW )
//@Transactional(rollbackFor = Exception.class,propagation= Propagation.NESTED)
@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRED )
public void testB(){
insertB(b);
throw new NullPointerException();
insertB(c);
}
1.执行a的入库(没有事务管理)=>a入库sql语句自动提交,直接入库成功
2.执行testB的时候会创建事务,管理b和c的入库,由于b执行完成抛出空指针异常,事务回滚,因此b入库失败
最终结果:只有a入库成功
REQUIRES_NEW
如果当前已经存在事务,新建事务
@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRED )
public void test() {
insertA(a);
testB();
throw new NullPointerException();
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void testB() {
updateB(b);
updateB(c);
}
1.创建事务A 事务A执行a的入库
2.执行testB的时候会挂起事务A并创建事务B,执行b和c的入库,提交事务B,恢复事务A
3.抛出异常,事务A回滚,也就是a并未真正入库
最终结果:b,c入库
NOT_SUPPORTED
如果当前存在事务,则挂起当前事务
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void test() {
insertA(a);
testB();
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NOT_SUPPORTED)
public void testB() {
updateB(b);
throw new NullPointerException();
updateB(c);
}
1.执行test的时候会创建事务A,管理a入库
2.执行testB的时候会挂起事务A,testB以非事务运行,b的入库语句自动提交,恢复事务A
3.方法testB抛出异常,并传递给方法test(),事务A回滚
最终结果:b入库
如果当前不存在事务,以非事务方式运行
SUPPORTS也适用于当前案例
public void test() {
insertA(a);
testB();
}
//@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NOT_SUPPORTED)
public void testB() {
updateB(b);
throw new NullPointerException();
updateB(c);
}
}
这个效果和没有加@Transation注解一样的,a,b,c的入库都没有事务管理
最终结果:a,b入库
NESTED
//@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void test() {
insertA(a);
try{
testB();
}catch(Exception e){
}
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void testB() {
updateB(b);
throw new NullPointerException();
updateB(c);
}
}
1.创建事务A,执行a的入库
2.从事务A创建子事务B,管理b和c的入库,在入库之前抛出异常,子事务回滚,子事务B回滚不会影响父事务A
3.事务A入库提交
4.最终结果:a入库
//@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void test() {
insertA(a);
testB();
throw new NullPointerException();
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void testB() {
updateB(b);
updateB(c);
}
}
1.创建事务A,执行a的入库
2.从事务A创建子事务B,事务B管理b和c的入库
3.抛出异常,父事务A要回滚,子事务B也需要回滚
4.最终结果:无数据入库