LambdaQueryWrapper遇上@Async

京东云开发者
• 阅读 10

作者:京东科技 张新磊

文章背景

最近在测试业务需求时通读了研发指定需求的代码,发现研发大佬们用到了如下的内容,有些内容我还不是十分的清楚,比如下述真实代码;作为后端大佬肯定炉火纯青,但是我刚刚看到这段代码时确实有点懵;

快速理解的方式
直接借助joycoder解释代码的能力就可以快速理解
LambdaQueryWrapper遇上@Async

于是乎有了下述的探索
LambdaQueryWrapper遇上@Async

但是我为了理解的透彻点还是又去翻找了一些其它资料做一个记录吧,后续万一在遗忘了也方便快速查找
LambdaQueryWrapper遇上@Async

MyBatis-Plus的LambdaQueryWrapper简介

LambdaQueryWrapper是MyBatis-Plus提供的一种类型安全的查询条件构造器,它利用Java 8的Lambda表达式特性,避免了硬编码字段名,提高了代码的可读性和可维护性。

基本用法示例

LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getName, "张三")
           .ge(User::getAge, 18)
           .orderByDesc(User::getCreateTime);
List userList = userMapper.selectList(queryWrapper);

LambdaQueryWrapper的优势

类型安全:通过方法引用而非字符串指定字段,编译器可检查类型
代码可读性高:链式调用,语义清晰
防止SQL注入:自动处理参数绑定
智能提示:IDE可自动补全字段名

Spring Boot的@Async异步处理

@Async是Spring框架提供的注解,用于标记方法为异步执行。被@Async注解的方法会在调用时立即返回,而实际执行将发生在单独的线程中。

基本配置

首先需要在Spring Boot启动类或配置类上添加@EnableAsync注解:

@SpringBootApplication
@EnableAsync
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

简单使用示例

@Service
public class AsyncService {

    @Async
    public void asyncMethod() {
        // 这个方法将在单独的线程中执行
        System.out.println("执行异步方法: " + Thread.currentThread().getName());
    }
}

LambdaQueryWrapper与@Async的结合实践

将两者结合使用可以实现高效的异步数据库操作,特别适合那些不需要立即返回结果的复杂查询或批量操作。

示例1:异步查询用户列表

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserMapper userMapper;

    @Async
    public CompletableFuture> asyncFindUsers(String name, Integer minAge) {
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(name), User::getName, name)
                   .ge(minAge != null, User::getAge, minAge);

        List users = userMapper.selectList(queryWrapper);
        return CompletableFuture.completedFuture(users);
    }
}

示例2:异步统计与保存

@Async
public void asyncStatAndSave(Long departmentId) {
    // 统计部门人数
    LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getDepartmentId, departmentId);
    long count = userMapper.selectCount(queryWrapper);

    // 更新统计结果
    Department department = new Department();
    department.setId(departmentId);
    department.setUserCount(count);
    departmentMapper.updateById(department);

    // 记录统计日志
    StatLog statLog = new StatLog();
    statLog.setDepartmentId(departmentId);
    statLog.setCount(count);
    statLog.setStatTime(LocalDateTime.now());
    statLogMapper.insert(statLog);
}

高级应用与优化

自定义线程池配置

默认情况下,@Async使用SimpleAsyncTaskExecutor,这不是生产环境的最佳选择。我们可以自定义线程池:

@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("AsyncExecutor-");
        executor.initialize();
        return executor;
    }
}

异常处理

异步方法的异常不会传播到调用线程,需要特别处理:

@Async
public CompletableFuture> asyncFindUsersWithExceptionHandling(String name) {
    try {
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getName, name);
        List users = userMapper.selectList(queryWrapper);
        return CompletableFuture.completedFuture(users);
    } catch (Exception e) {
        // 记录日志
        log.error("异步查询用户失败", e);
        // 返回空列表或抛出CompletionException
        return CompletableFuture.completedFuture(Collections.emptyList());
    }
}

事务处理

@Async方法的事务需要特别注意,默认情况下异步方法的事务不会传播:

@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncUpdateWithTransaction(User user) {
    // 这个更新操作将在新事务中执行
    userMapper.updateById(user);
}

LambdaQueryWrapper遇上@Async

实际应用场景

后台报表生成

@Async
public void asyncGenerateUserReport(LocalDate startDate, LocalDate endDate, String reportPath) {
    LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.between(User::getCreateTime, startDate.atStartOfDay(), endDate.atTime(23, 59, 59))
               .orderByAsc(User::getCreateTime);

    List users = userMapper.selectList(queryWrapper);

    // 生成报表文件
    generateExcelReport(users, reportPath);

    // 发送通知
    sendReportReadyNotification(reportPath);
}

批量数据处理

@Async
public CompletableFuture asyncBatchProcessUsers(List userIds) {
    LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.in(User::getId, userIds);

    List users = userMapper.selectList(queryWrapper);

    int processedCount = 0;
    for (User user : users) {
        if (processUser(user)) {
            processedCount++;
        }
    }
    return CompletableFuture.completedFuture(processedCount);
}

LambdaQueryWrapper遇上@Async

性能考量与最佳实践

合理使用异步:不是所有数据库操作都适合异步,简单查询同步执行可能更高效
控制并发量:避免过多并发数据库连接导致系统资源耗尽
批量操作优化:考虑使用MyBatis-Plus的批量操作方法
结果处理:使用CompletableFuture可以方便地处理异步结果
监控:监控异步任务的执行情况和线程池状态

总结

MyBatis-Plus的LambdaQueryWrapper与Spring Boot的@Async注解的结合,为Java后端开发提供了强大的工具组合。LambdaQueryWrapper提供了类型安全、优雅的查询构建方式,而@Async则让异步编程变得简单。合理使用这两者可以显著提高应用程序的响应速度和处理能力,特别是在处理复杂查询、批量操作和后台任务时。
在实际项目中,开发者应根据具体场景选择合适的技术组合,并注意线程池配置、异常处理和事务管理等关键点,以确保系统的稳定性和可靠性。

点赞
收藏
评论区
推荐文章
DevOpSec DevOpSec
2年前
限制linux用户访问特定目录-centos沙箱环境
背景研发需求:1.研发想查看线上服务日志2.研发要看线上部署代码是否正确3.研发想看业务运行时产生数据是否正确运维需求:1.运维不想让研发有太多权限2.只有产看某些特定目录的权限和产看日志问题:研发具有太多权限后,对线上风险影响较大,比如研发误操作删文件跑
顺心 顺心
4年前
带你全面了解 Flutter,它好在哪里?它的坑在哪里? 应该怎么学?
回顾了这段时间解答关于Flutter的各种问题后,我突然发现很多刚刚接触Flutter的萌新,对于Flutter都有着不同程度的误解,而每次重复的解释又十分浪费时间,最终我还是决定写篇文章来做个总结。内容有点长,但是相信能帮你更好地去认识Flutter。Flutter的起源Flutter的诞生其实比较有意思,Flutter
京东云开发者 京东云开发者
11个月前
「重构:改善既有代码的设计」实战篇
背景在软件开发的世界里,代码重构是提升项目质量、适应业务变化的关键步骤。最近,我重新翻阅了《重构:改善既有代码的设计第二版》,这本书不仅重新点燃了我对重构的热情,还深化了我的理解:重构不仅仅是代码层面的整理,它更是一种软件开发的哲学,强调持续改进和适应变化
精准测试探索 | 京东云技术团队
什么是精准测试?通常研发提测的需求有代码变更,针对研发的代码变更点以及关联点进行测试,我们称之为精准测试。
Python进阶者 Python进阶者
1年前
python项目导入上级目录设置”的setting.json是不是哪里还有错误呀?
大家好,我是Python进阶者。一、前言前几天在Python白银交流群【王者级混子】问了一个Python代码处理的问题,问题如下:大佬们,我想问问我抄网上“vscode运行python项目导入上级目录设置”的setting.json是不是哪里还有错误呀?还
Python进阶者 Python进阶者
2年前
盘点一个Python自动化办公需求,实现数据自动填充
大家好,我是皮皮。一、前言前几天遇到了一个小需求,粉丝自己在实际工作中的需求,需要把下图的表格内容,自动填充到目标表格中去,省得挨个去复制粘贴了,而且还十分容易出错。原始表格如下图所示:目标表格如下图所示:二、实现过程这里【枫涧澈浪】大佬给了一个代码,如下
京东云开发者 京东云开发者
8个月前
飞码LowCode前端技术(七)
作者:京东科技王光辉简介飞码是京东科技市场与平台运营中心平台研发部研发低代码产品,可使营销运营域下web页面快速搭建。飞码是单web页面搭建工具,从创建页面到监测再到投产的一站式解决方案。会通过七篇文章介绍飞码,分别是:(1)、背景与数据结构设计,(2)、
京东云开发者 京东云开发者
8个月前
飞码LowCode前端技术(六)
作者:京东科技王光辉(如何便捷快速验证实现投产及飞码探索)\作者:王光辉\部门:京东科技市场与平台运营中心营销与数据资产部营销及数据平台研发部简介飞码是京东科技市场与平台运营中心平台研发部研发低代码产品,可使营销运营域下web页面快速搭建。飞码是单web页
京东云开发者 京东云开发者
8个月前
飞码LowCode前端技术(五)
作者:京东科技王光辉简介飞码是京东科技市场与平台运营中心平台研发部研发低代码产品,可使营销运营域下web页面快速搭建。飞码是单web页面搭建工具,从创建页面到监测再到投产的一站式解决方案。会通过七篇文章介绍飞码,分别是:(1)、背景与数据结构设计,(2)、
京东云开发者 京东云开发者
2个月前
探索Playwright:前端自动化测试的新纪元
作者:京东科技张新磊背景在前端开发中,自动化测试是确保软件质量和用户体验的关键环节。随着Web应用的复杂性不断增加,手动测试已经无法满足快速迭代和持续交付的需求。自动化测试通过模拟用户与应用的交互,能够高效地执行重复性测试任务,加快测试周期,提升测试覆盖率