spring事务嵌套的三大混淆点,嵌套事务,默认事务管理器

spring事务传播机制分类

	首先贴出spring所有传播机制,使用很简单,在service层进行类注解或者方法注解 @Transactional(propagation = Propagation.XXXX),当然也可以配置事物切面,进行切面操作
事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

事务嵌套的三大混淆点

	spring的事物管理相对来讲比较简单,但仍然有比较容易引起混淆的点,此段落只做列举,下段落会有详细讲解
  1. @Transactional(propagation = Propagation.REQUIRED) 如果当前有则使用当前事务
  2. @Transactional(propagation = Propagation.NESTED)利用sql的savepoint进行嵌套事务
  3. @Transactional(propagation =Propagation.REQUIRES_NEW) 开启新的事务

项目背景:

springboot 2.1.0.RELEASE + jpa + jpa默认实现hibernate

jpa默认事务管理器为PlatformTransactionManager默认实现类JpaTransactionManager

JpaTransactionManager默认不开启嵌套事务Propagation.NESTED

需要手动开启,操作如下

//实现借口
@Configuration
public class DatasourceConfig implements TransactionManagementConfigurer{

@Autowired
private PlatformTransactionManager ps;
  
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
  //验证系统所使用的事物控制器
  System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
   
  return null;
}
 @Override
 public PlatformTransactionManager annotationDrivenTransactionManager() {
        
   JpaTransactionManager jm = (JpaTransactionManager)ps;
   //允许事物嵌套,默认false 
   jm.setNestedTransactionAllowed(true);
        
   return jm;
  }

}

junit事务回滚触发机制:

使用spring的测试模块,事务默认为回滚

@test方法开启事务默认回滚,需手动关闭
@Test
@Transactional
@Rollback(false)

事务嵌套使用说明:

	所有异常均为runtimeexception子类(也可自己设置)

REQUIRES_NEW 在父级方法中调用,开启新的事务,回滚与否只与本方法有关,父级方法进行捕获异常操作后,可以防止父级方法回滚
REQUIRED 在父级方法中调用,沿用父级事务,如果本方法抛出异常,无论父级方法是否捕获,都会引起父级与本方法的回滚,因为他们属于一个事务,事务切面同时监控两个方法,出现异常即回滚
NESTED 在父级方法中调用,类似于REQUIRED,但如果父级方法进行捕获异常,整个事务中将只会回滚本方法中的数据库操作,父级方法可以根据异常情况进行后续操作,决定整体回滚还是部分提交;如果本方法无异常,父级方法出现异常,本方法与父级方法都会回滚

	总结,REQUIRES_NEW与NESTED的不同在于,父级方法无法控制REQUIRES_NEW的回滚操作;NESTED与REQUIRED的不同在于,REQUIRED无法实现提交父级方法的同时,忽略子方法的异常。

代码测试案例:

	下述案例中,delete方法出现异常但属于nested嵌套事务,contextLoads对异常进行捕获,故不引起contextLoads方法回滚,但是如果delete方法为REQUIRED,无论contextLoads是否进行捕获,都会引起contextLoads回滚,因为属于一个事务,事务管理器也会对delete方法进行切面操作,delete方法出现异常,整体回滚
@Test
@Transactional
@Rollback(false)
public void contextLoads() {
	User u = new User();
	u.setName(“ln”);
	userService.save(u);
	try {
		userService.delete(u.getId());
	}catch(Exception e) {
		e.printStackTrace();
	}
	System.out.println("----------------------------");
}
@Service
public class UserService {

  @Resource
  private UserDao userDao;
  
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void save(User user) {
        
        //jdbcTemplet.execute("insert into user value('1','ln')");
        userDao.save(user);
        
  }
  
  @Transactional(propagation = Propagation.NESTED)
  public void delete(int id) {
        userDao.deleteById(id);
        //jdbcTemplet.execute("delete from user where id = '2'");
        //除零异常抛出
        int x = 1/0;
        System.out.println(x);
  }

}

你可能感兴趣的:(技术spring事务)