13_spring传播行为总结

本文详细解释了Spring框架中的事务传播行为,包括REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER和NESTED等策略,以及它们在不同场景下的执行逻辑和影响。特别强调了NESTED模式的独特性,允许内部事务独立于外部事务回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传播行为

传播行为说明
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_NESTEDPropagation.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这三个之间比较绕。需要好好理解以及代码的测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值