实际项目中应该避免@Async注解同类调用问题

同类中调用有@Async注解的方法异步不生效,

其实@Async的这个性质在官网上已经有过说明了,官网:https://www.baeldung.com/spring-async是这样说的:

“First – let’s go over the rules – @Async has two limitations:
it must be applied to public methods only
self-invocation – calling the async method from within the same class – won’t work
The reasons are simple – 「the method needs to be public」 so that it can be proxied. And 「self-invocation doesn’t work」 because it bypasses the proxy and calls the underlying method directly.”

@Async的两个限制,第一个是必须在public修饰的情况下使用,第二个就是调用自己类上的异步方法是不起作用的。

原因:注解其实是通过代理的方式来实现异步调用的。同理@Transactional注解也是

实践

之前项目中会发生使用不当的情况:

 /**
 * @author lzq
 * @date
 */
 	public Integer delete(PointAccountDTO pointAccountDTO) {
        QueryWrapper<PointAccountDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", pointAccountDTO.getId()).last("limit 1");
        PointAccountDO pointAccountDO = pointAccountMapper.selectOne(queryWrapper);
        int count = pointAccountMapper.delete(queryWrapper);
        if (count > 0) {
            deleteMemberAnalysisPoints(pointAccountDTO.getId());
            deleteGradeConditionPoints(pointAccountDO.getCode());
        }
        return count;
    }

    @Async
    @Transactional
    public void deleteMemberAnalysisPoints(String id){}
     
    @Async
    @Transactional
    public void deleteGradeConditionPoints(String code){}

正确使用场景,先建立异步工具类

@Component
@Slf4j
public class AsyncUtils {

    private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(1, 5, 60,
            TimeUnit.MINUTES, new ArrayBlockingQueue<>(512));
    @Resource
    private AsyncTaskMapper asyncTaskMapper;

    public void execute(Runnable runnable, String param, String taskDesc) {
        AsyncTaskDO asyncTaskDO = AsyncTaskDO.builder()
                .param(param)
                .taskDesc(taskDesc)
                .build();
        asyncTaskMapper.insert(asyncTaskDO);
        EXECUTOR.submit(new TenantRunnableWrap(runnable, asyncTaskMapper, asyncTaskDO));

    }


    @Slf4j
    static class TenantRunnableWrap implements Runnable {
        private final Runnable task;
        private final AsyncTaskMapper asyncTaskMapper;
        private final AsyncTaskDO asyncTaskDO;

        public TenantRunnableWrap(Runnable task, AsyncTaskMapper asyncTaskMapper, AsyncTaskDO asyncTaskDO) {
            this.task = task;
            this.asyncTaskMapper = asyncTaskMapper;
            this.asyncTaskDO = asyncTaskDO;
        }

        @Override
        public void run() {
            try {
                task.run();
            } catch (Exception e) {
                asyncTaskDO.setExceptionDesc(e.getMessage());
                asyncTaskMapper.updateById(asyncTaskDO);
                return;
            }
            asyncTaskMapper.deleteById(asyncTaskDO);
        }
    }
}

先注入

@Autowired
private AsyncUtils asyncUtils;

注意,为了要让事务生效,一定要注入自身类

@Lazy
@Resource
PointAccountService pointAccountService;

使用

@Override
@Transactional
public Integer delete(PointAccountDTO pointAccountDTO) {
        QueryWrapper<PointAccountDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", pointAccountDTO.getId()).last("limit 1");
        PointAccountDO pointAccountDO = pointAccountMapper.selectOne(queryWrapper);
        int count = pointAccountMapper.delete(queryWrapper);
        if (count > 0) {
            asyncUtils.execute(() -> pointAccountService.deleteMemberAnalysisPoints(pointAccountDTO.getId()), 
                    String.valueOf(pointAccountDTO.getId()),
                    "异步删除成员积分");
            asyncUtils.execute(() -> pointAccountService.deleteGradeConditionPoints(pointAccountDO.getCode()),
                    pointAccountDO.getCode(),
                    "异步删除等级积分");
//            deleteMemberAnalysisPoints(pointAccountDTO.getId());
//            deleteGradeConditionPoints(pointAccountDO.getCode());
        }
        return count;
    }

@Transactional
public void deleteGradeConditionPoints(String code) {}

在这里插入图片描述
执行是为了存表方便记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值