同类中调用有@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) {}
执行是为了存表方便记录