Boost Java Backend Performance with MyBatis-Plus LambdaQueryWrapper and Spring @Async

Learn how to combine MyBatis-Plus's type‑safe LambdaQueryWrapper with Spring Boot's @Async annotation to build readable, maintainable queries and execute them asynchronously, including configuration of custom thread pools, exception handling, transaction management, and practical use cases such as reporting and batch processing.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Boost Java Backend Performance with MyBatis-Plus LambdaQueryWrapper and Spring @Async

Article Background

While testing business requirements, the author encountered backend code using MyBatis-Plus LambdaQueryWrapper and Spring Boot @Async, which prompted a deeper exploration.

Introduction to MyBatis-Plus LambdaQueryWrapper

LambdaQueryWrapper is a type‑safe query builder provided by MyBatis‑Plus. It leverages Java 8 lambda expressions to avoid hard‑coded field names, improving readability and maintainability.

Basic Usage Example

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

Advantages of LambdaQueryWrapper

Type safety: compiler checks field references.

High readability: fluent, chainable API.

SQL injection prevention: parameters are bound automatically.

IDE assistance: auto‑completion of field names.

Spring Boot @Async Asynchronous Processing

@Async marks a method for asynchronous execution. The method returns immediately while the actual work runs in a separate thread.

Basic Configuration

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

Simple Usage Example

@Service
public class AsyncService {
    @Async
    public void asyncMethod() {
        // This method runs in a separate thread
        System.out.println("Executing async method: " + Thread.currentThread().getName());
    }
}

Combining LambdaQueryWrapper with @Async

Using both enables efficient asynchronous database operations, suitable for complex queries or batch tasks that do not require immediate results.

Example 1: Asynchronous User Query

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserMapper userMapper;

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

Example 2: Asynchronous Statistics and Save

@Async
public void asyncStatAndSave(Long departmentId) {
    // Count users in department
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getDepartmentId, departmentId);
    long count = userMapper.selectCount(queryWrapper);

    // Update department statistics
    Department department = new Department();
    department.setId(departmentId);
    department.setUserCount(count);
    departmentMapper.updateById(department);

    // Log statistics
    StatLog statLog = new StatLog();
    statLog.setDepartmentId(departmentId);
    statLog.setCount(count);
    statLog.setStatTime(LocalDateTime.now());
    statLogMapper.insert(statLog);
}

Advanced Usage and Optimization

Custom Thread‑Pool Configuration

@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;
    }
}

Exception Handling

@Async
public CompletableFuture<List<User>> asyncFindUsersWithExceptionHandling(String name) {
    try {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getName, name);
        List<User> users = userMapper.selectList(queryWrapper);
        return CompletableFuture.completedFuture(users);
    } catch (Exception e) {
        log.error("Async user query failed", e);
        return CompletableFuture.completedFuture(Collections.emptyList());
    }
}

Transaction Management

@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncUpdateWithTransaction(User user) {
    // This update runs in a new transaction
    userMapper.updateById(user);
}

Practical Application Scenarios

Backend Report Generation

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

Batch Data Processing

@Async
public CompletableFuture<Integer> asyncBatchProcessUsers(List<Long> userIds) {
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.in(User::getId, userIds);
    List<User> users = userMapper.selectList(queryWrapper);
    int processedCount = 0;
    for (User user : users) {
        if (processUser(user)) {
            processedCount++;
        }
    }
    return CompletableFuture.completedFuture(processedCount);
}

Performance Considerations & Best Practices

Use async only where it truly benefits performance; simple queries may be faster synchronously.

Control concurrency to avoid exhausting database connections.

Leverage MyBatis‑Plus batch operations for bulk updates.

Handle results with CompletableFuture for flexible post‑processing.

Monitor async task execution and thread‑pool health.

Conclusion

Combining MyBatis‑Plus's LambdaQueryWrapper with Spring Boot's @Async provides a powerful toolkit for Java backend development. LambdaQueryWrapper offers type‑safe, expressive query construction, while @Async simplifies asynchronous programming. Proper configuration of thread pools, exception handling, and transaction management ensures stable, high‑performance applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootMyBatis-PlusasyncLambdaQueryWrapper
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.