作者:京东科技 张新磊
文章背景
最近在测试业务需求时通读了研发指定需求的代码,发现研发大佬们用到了如下的内容,有些内容我还不是十分的清楚,比如下述真实代码;作为后端大佬肯定炉火纯青,但是我刚刚看到这段代码时确实有点懵;
快速理解的方式
直接借助joycoder解释代码的能力就可以快速理解
于是乎有了下述的探索
但是我为了理解的透彻点还是又去翻找了一些其它资料做一个记录吧,后续万一在遗忘了也方便快速查找
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);
}
实际应用场景
后台报表生成
@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);
}
性能考量与最佳实践
合理使用异步:不是所有数据库操作都适合异步,简单查询同步执行可能更高效
控制并发量:避免过多并发数据库连接导致系统资源耗尽
批量操作优化:考虑使用MyBatis-Plus的批量操作方法
结果处理:使用CompletableFuture可以方便地处理异步结果
监控:监控异步任务的执行情况和线程池状态
总结
MyBatis-Plus的LambdaQueryWrapper与Spring Boot的@Async注解的结合,为Java后端开发提供了强大的工具组合。LambdaQueryWrapper提供了类型安全、优雅的查询构建方式,而@Async则让异步编程变得简单。合理使用这两者可以显著提高应用程序的响应速度和处理能力,特别是在处理复杂查询、批量操作和后台任务时。
在实际项目中,开发者应根据具体场景选择合适的技术组合,并注意线程池配置、异常处理和事务管理等关键点,以确保系统的稳定性和可靠性。