当@Transtctional遇到@Async遇碰撞出怎样的火花?

上篇讲述了@Transtctional下调用@Async异步执行,然后token失效的问题:

记一次SpringCloud OpenFeign 服务调用传递 token @Async 上下文信息获取失败

本篇则详细讲述两者互存的各种场景及其使用注意事项。

一、@Transtctional @Async概念

@Transactional注解是Spring框架提供的一个用于声明式事务管理的注解。它可以应用在方法或类上,用于标识需要进行事务管理的方法或类。通过使用@Transactional注解,我们可以更加方便地管理事务,保障数据的一致性和可靠性

@Async 是 Spring 框架提供的注解,用于将方法标记为异步执行。通过使用 @Async 注解,可以告知 Spring 在调用被注解的方法时,使用新的线程或线程池进行异步执行。

二、调用场景复现,加入注解看是否回滚?

说明: @Transaction方法 服务于 saveInspectInfo() ;@Async 服务于testAsync()两者位于不同的两个类里边

1)saveInspectInfo() 加注解;testAsync()无注解

@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveInspectInfo() {
		taskInspectMapper.updateDataStatus(126387703699750912L);
		asyncTest.testAsync();
	}

public void testAsync(){
		log.info("testAsync threadName="+Thread.currentThread().getName());
		TaskInspect taskInspect=new TaskInspect();
		taskInspect.setProject("sss");
		taskInspectMapper.insertSelective(taskInspect);
	}

在这里插入图片描述
.updateDataStatus(126387703699750912L) 的dataStatus更新为3;但是执行第二个方法的时候失败了,最终结果 回滚成功,说明事物生效;
在这里插入图片描述

2)saveInspectInfo() 加注解;testAsync()也加注解

2-1) saveInspectInfo() 执行成功;testAsync() 执行失败,是否回滚?

@Async("asyncServiceExecutor")
	public void testAsync(){
		log.info("testAsync threadName="+Thread.currentThread().getName());
		TaskInspect taskInspect=new TaskInspect();
		taskInspect.setProject("sss");
		taskInspectMapper.insertSelective(taskInspect);
	}

在这里插入图片描述
我们可以看到 testAsync()开启了一个新的线程来执行的,最终结果是.updateDataStatus(126387703699750912L) 的dataStatus更新为3,回滚失败。
在这里插入图片描述

2-2)saveInspectInfo() 执行失败;testAsync() 执行成功,是否回滚?

@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveInspectInfo() {
		taskInspectMapper.updateDataStatus(126387703699750912L);
		asyncTest.testAsync();
		TaskInspect taskInspect=new TaskInspect();
		taskInspect.setProject("sss");
		taskInspectMapper.insertSelective(taskInspect);
	}

@Async("asyncServiceExecutor")
	public void testAsync(){
		log.info("testAsync threadName="+Thread.currentThread().getName());
		taskInspectMapper.updateDataStatus(126979559810678784L);
	}

在这里插入图片描述
通过结果可以看到两个更新方法都走了,两个线程,猜测结果是咋样的?那肯定是一个成功一个失败呗。有事物的回滚,异步的执行成功。
在这里插入图片描述

2-3)saveInspectInfo() 执行失败,还未触发到异步操作。

@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveInspectInfo() {
		taskInspectMapper.updateDataStatus(126387703699750912L);
		TaskInspect taskInspect=new TaskInspect();
		taskInspect.setProject("sss");
		taskInspectMapper.insertSelective(taskInspect);
		asyncTest.testAsync();
	}

在这里插入图片描述
testAsync()并未执行。所以两者状态都不变。

三、我就想让方法A执行完毕之后再异步执行方法B,如何处理?

就拿刚才的偏激场景来说事,我就想着方法A中的下单操作成功完成之后再走方法B,扣减库存。

@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveInspectInfo() {
		//事物操作方法1
		taskInspectMapper.updateDataStatus(126387703699750912L);
		//异步方法操作
		asyncTest.testAsync();
		//回滚
		TaskInspect taskInspect = new TaskInspect();
		taskInspect.setProject("sss");
		//事物操作方法2
		taskInspectMapper.insertSelective(taskInspect);
		//事物操作方法3
		taskInspectMapper.updateDataStatus(126389155885236224L);
	}

如上代码,执行结果:操作方法1执行成功,但是回滚;异步操作执行成功;操作方法2失败导致的事物回滚;操作方法3未执行。
在这里插入图片描述
我想要的结果并非如此,想象的是,三个事物操作方法都执行成功了,才执行异步操作

// 给当前线程注册一个事务同步器
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
			@Override
			public void afterCompletion(int status) {
				// 保证事务一定是已经提交了
				if (TransactionSynchronization.STATUS_COMMITTED == status) {
					// 异步方法写这里
					.......
				}
			}
		});
@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveInspectInfo() {
		//事物操作方法1
		taskInspectMapper.updateDataStatus(126387703699750912L);

		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
			@Override
			public void afterCompletion(int status) {
				// 保证事务一定是已经提交了
				if (TransactionSynchronization.STATUS_COMMITTED == status) {
					//异步方法操作
					asyncTest.testAsync();
				}
			}
		});
		//回滚
		TaskInspect taskInspect = new TaskInspect();
		taskInspect.setProject("sss");
		//事物操作方法2
		taskInspectMapper.insertSelective(taskInspect);
		//事物操作方法3
		taskInspectMapper.updateDataStatus(126389155885236224L);
	}

虽然按照顺序,我的异步注解在操作方法1后边,比较靠前,但是不影响我等待整个事物的成功执行后再提交。
在这里插入图片描述

四、两者碰撞注意事项

1)方法A和方法B不能同处于同一个类中。

因为 @Transactional 和 @Async 注解的实现都是基于 Spring 的 AOP ,而 AOP 的实现是基于动态代理实现的,故Async 失效的原理和原理是一样的。
所以要想两个注解都生效,必须保证是不同的类,保证是通过代理类去执行操作。

2)方法B尽量不要依赖方法A的相应操作。

举例说明:比如 方法A我执行了下单操作,想着用异步的方式去扣减库存,这种方式是严格禁止的,风险太大了。就是拿最偏激的场景来说一下这个事情。

3)异步方法尽量写到方法最后面,这样按照顺序,假如中间某个方法失败了,直接就回滚了,不会走到异步方法内,假如某个场景,异步注解就在中间或者偏上位置,那么就直接加事物同步器就可。

  • 19
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Async方法是Spring框架中的一种特殊注解,用于实现异步方法调用。通过在方法上添加@Async注解,可以告诉Spring容器该方法应该在单独的线程中执行,而不会阻塞当前线程的执行。\[1\] 要使用@Async方法调用,需要按照以下步骤进行操作: 1. 在启动类上添加@EnableAsync注解,以启用异步功能。\[2\] 2. 在需要异步执行的方法上添加@Async注解。这样,当调用该方法时,Spring会自动将其放入线程池中执行,并返回一个Future对象,用于获取异步方法的执行结果。\[3\] 例如,假设我们有一个名为doSomething的方法需要异步执行,我们可以在方法上添加@Async注解,如下所示: ```java @Async public Future<String> doSomething() { // 异步执行的逻辑 return new AsyncResult<>("异步方法执行结果"); } ``` 在调用doSomething方法时,它将在单独的线程中执行,并返回一个Future对象。我们可以使用该对象来获取异步方法的执行结果,如下所示: ```java Future<String> futureResult = doSomething(); String result = futureResult.get(); // 获取异步方法的执行结果 ``` 通过使用@Async方法调用,我们可以实现并发执行任务,提高系统的响应性能和吞吐量。同时,它也可以帮助我们处理那些不需要立即返回结果的耗时操作,提高系统的并发处理能力。 #### 引用[.reference_title] - *1* *3* [在Spring中使用Future对象调用Async方法调用](https://blog.csdn.net/dnc8371/article/details/106705454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Spring中使用@Async异步调用方法](https://blog.csdn.net/qq_34178998/article/details/95939425)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值