传播行为
传播行为 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。 |
PROPAGATION_SUPPORTS | 如果当前没有事务,就以非事务方式执行,如果已经存在一个事务中,加入到这个事务中 |
PROPAGATION_MANDATORY | 如果当前没有事务,就抛出异常,如果已经存在一个事务中,加入到这个事务中 |
PROPAGATION_REQUIRES_NEW | 如果当前没有事务,就新建事务,如果当前存在事务,把当前事务挂起并新建事务 |
PROPAGATION_NOT_SUPPORTED | 如果当前没有事务,就以非事务执行,如果当前存在事务,就把当前事务挂起并以非事务运行 |
PROPAGATION_NEVER | 如果当前没有事务,就以非事务执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前没有事务,就新建一个事务,如果当前存在事务,则在嵌套事务内执行。 |
下面我们一个一个来进行测试:
代码:
@ComponentScan("com.gl")//
@Configuration
@EnableTransactionManagement
@EnableAspectJAutoProxy
@MapperScan("com.gl.mapper")
public class AppConfig {
@Bean
public MysqlDataSource dataSource(){
MysqlDataSource dataSource = new MysqlDataSource();
// dataSource.("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://10.9.0.123:3306/gl_dys_msme?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true&rewriteBatchedStatements=true");
dataSource.setPassword("123456");
dataSource.setUser("root");
return dataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactoryBean sqlSessionFactoryBean(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("com/gl/mapper/SysUserMapper.xml"));
return sqlSessionFactoryBean;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource());
return dataSourceTransactionManager;
}
}
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private SysUserService sysUserService;
@Autowired
private SysUserMapper sysUserMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void saveOrder() {
SysUser sysUser = new SysUser();
sysUser.setName("das");
sysUserMapper.save(sysUser);
sysUserService.save();
System.out.println(1/0);
}
}
@Service
public class SysUserServiceImpl implements SysUserService{
@Autowired
private SysUserMapper sysUserMapper;
@Override
// @Transactional(propagation = Propagation.NEVER) //有事务报错 ,无事务就无事务
// @Transactional(propagation = Propagation.SUPPORTS) //有事务用事务,无事务就无事务
// @Transactional(propagation = Propagation.NOT_SUPPORTED) //有事务,挂起事务 以无事务运行
@Transactional(propagation = Propagation.REQUIRED)//有事务用事务,无事务就新建事务
// @Transactional(propagation = Propagation.REQUIRES_NEW)//有没有事务都新建事务
// @Transactional(propagation = Propagation.MANDATORY)//没有事务就报错
// @Transactional(propagation = Propagation.NESTED)//有事务就嵌套事务,没事务就新建事务
public void save() {
SysUser sysUser = new SysUser();
sysUser.setName("das");
sysUserMapper.save(sysUser);
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com");
OrderService orderService =(OrderService) applicationContext.getBean("orderServiceImpl");
orderService.saveOrder();
}
}
1、Propagation.REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中
①外部无事务,内部使用Propagation.REQUIRED并报错
外部方法保存成功,内部方法回滚
②外部存在事务,内部使用Propagation.REQUIRED并报错
外部方法保存回滚,内部方法回滚 。两者使用同一事务
外部有事务,内部加入事务并且是同一事物。外部没有事务,内部就新建一个事务。
2、PROPAGATION_SUPPORTS
如果当前没有事务,就以非事务方式执行,如果已经存在一个事务中,加入到这个事务中
①外部无事务,内部使用PROPAGATION_SUPPORTS并报错
外部方法保存成功,内部方法保存成功 都没有使用事务
②外部存在事务,内部使用PROPAGATION_SUPPORTS并报错
外部方法保存回滚,内部方法回滚 。两者都是用事务并且是同一事务
外部有事务,内部加入事务并且是同一事务。外部无事务,内部也无事务
3、PROPAGATION_MANDATORY
如果当前没有事务,就抛出异常,如果已经存在一个事务中,加入到这个事务中
①外部无事务,内部使用PROPAGATION_MANDATORY并报错
外部保存成功,内部直接抛异常(No existing transaction found for transaction marked with propagation ‘mandatory’)
②外部有事务,内部使用PROPAGATION_MANDATORY并报错
外部回滚,内部回滚 。两者都是用事务并且是同一事务
外部有事务,内部加入事务并且是同一事务。外部没有事务,内部就抛异常
4、PROPAGATION_REQUIRES_NEW
如果当前没有事务,就新建事务,如果当前存在事务,把当前事务挂起并新建事务
①外部无事务,内部使用PROPAGATION_REQUIRES_NEW并报错
外部保存成功,内部回滚。
②外部有事务报错,内部使用PROPAGATION_REQUIRES_NEW
外部回滚,内部保存成功
外部有事务,内部也新建事务将外部事物挂起是两个事务,即使外部回滚也不影响内部事务的提交。外部没有事务,内部新建事务
5、PROPAGATION_NOT_SUPPORTED
①外部无事务,内部使用PROPAGATION_NOT_SUPPORTED并报错
外部保存成功,内部保存成功
②外部有事务报错,内部使用PROPAGATION_NOT_SUPPORTED并报错
外部回滚,内部保存成功
外部有事务,内部会将事务挂起并使用无事务运行。外部无事务,内部也不用事务
6 、PROPAGATION_NEVER
①外部无事务,内部使用PROPAGATION_NEVER并报错
外部保存成功,内部保存成功
②外部有事务报错,内部使用PROPAGATION_NEVER
外部保存失败,内部抛异常(Existing transaction found for transaction marked with propagation ‘never’)
外部有事务,内部抛异常。外部无事务,内部也不用事务。
7 、PROPAGATION_NESTED
①外部无事务,内部使用PROPAGATION_NEVER并报错
外部保存成功,内部回滚
②外部有事务,内部使用PROPAGATION_NEVER并报错
外部回滚,内部回滚,但当将内部方法捕获异常后 外部会提交事务,内部回滚
②外部有事务报错,内部使用PROPAGATION_NEVER
外部回滚,内部回滚
外部没有事务,新建事务。外部有事务,就在嵌套事务内运行
疑问:
这里面大家肯定会疑惑那PROPAGATION_NESTED和Propagation.REQUIRED岂不是没有区别。
区别就在 在调用内部方法时有没有try catch。如果是Propagation.REQUIRED即使try catch了内部外部还是都会回滚,原因是内部外部属于同一个事务。但PROPAGATION_NESTED不同,当你没有try catch是内部外部会回滚。但当你try catch后,外部不会回滚,而内部会回滚。 那么PROPAGATION_NESTED它的意思就是内部事务完全可以作为一个独立的事务处理,而不影响外部事物,但需要进行捕获异常。
那这里又会有一个问题,那既然作为独立的事务岂不是又和PROPAGATION_REQUIRES_NEW相同了。
这个又要从外部事务来看,如果外部方法抛异常,由于PROPAGATION_REQUIRES_NEW是新建一个事务,并不会影响到内部方法的提交。而PROPAGATION_NESTED由于是同一事务会影响到内部方法的提交。
总结:
PROPAGATION_NESTED
一个事务
内部报错可以使用try catch来进行内部事务 回滚 而不影响外部事务。
外部报错会影响内部事务
PROPAGATION_REQUIRES_NEW
两个事务
内部报错也可以使用try catch来进行内部事务 回滚 而不影响外部事务。
外部事务报错不会影响内部事务
Propagation.REQUIRED
一个事务
内部事务报错,总会影响外部事务
外部事务报错会影响内部事务
对于PROPAGATION_NESTED、PROPAGATION_REQUIRES_NEW、Propagation.REQUIRED这三个之间比较绕。需要好好理解以及代码的测试。