Simplified Join Queries with MyBatis-Plus-Join (MPJ) in Spring Boot
This tutorial demonstrates how to use the MyBatis-Plus-Join (MPJ) library to perform left and right join queries in a Spring Boot project without writing XML SQL, covering dependency setup, mapper modification, query construction with MPJLambdaWrapper and MPJQueryWrapper, and pagination support.
MyBatis-Plus is a widely used enhancement for MyBatis, yet its join query capabilities have traditionally required manual XML SQL for left or right joins, which many developers find cumbersome.
The author introduces mybatis-plus-join (referred to as mpj ), a tool that enables join queries using the familiar QueryWrapper style, effectively freeing developers from XML‑based SQL.
Dependency Introduction – Add the following Maven dependencies to the project:
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>After adding the dependencies, configure the data source in the usual Spring Boot way.
Data Preparation – Create three tables (order, user, product) to demonstrate the join queries.
Mapper Modification – Replace the default BaseMapper inheritance with MPJBaseMapper for each entity. Example for the order table:
@Mapper
public interface OrderMapper extends MPJBaseMapper<Order> {
}Optionally, services can extend MPJBaseService and MPJBaseServiceImpl , though this is not mandatory.
Join Query with MPJLambdaWrapper – The following method shows a complete left‑join query without writing any SQL:
public void getOrder() {
List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,
new MPJLambdaWrapper<Order>()
.selectAll(Order.class)
.select(Product::getUnitPrice)
.selectAs(User::getName, OrderDto::getUserName)
.selectAs(Product::getName, OrderDto::getProductName)
.leftJoin(User.class, User::getId, Order::getUserId)
.leftJoin(Product.class, Product::getId, Order::getProductId)
.eq(Order::getStatus, 3));
list.forEach(System.out::println);
}The MPJLambdaWrapper builds the query conditions, where selectAll() selects all fields of the main entity, select() adds specific columns, selectAs() maps column aliases to DTO fields, and leftJoin() defines the join relationships.
MPJQueryWrapper – For developers who prefer string‑based column specifications, the same query can be written with MPJQueryWrapper :
public void getOrderSimple() {
List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,
new MPJQueryWrapper<Order>()
.selectAll(Order.class)
.select("t2.unit_price", "t2.name as product_name")
.select("t1.name as user_name")
.leftJoin("t_user t1 on t1.id = t.user_id")
.leftJoin("t_product t2 on t2.id = t.product_id")
.eq("t.status", "3"));
list.forEach(System.out::println);
}When using MPJQueryWrapper , table aliases (e.g., t for the main table, t1 , t2 for joined tables) must be used instead of the actual database table names.
Pagination Support – MPJ also works with MyBatis‑Plus pagination. First, register the pagination interceptor:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}Then use selectJoinPage() to obtain a paged result set:
public void page() {
IPage<OrderDto> orderPage = orderMapper.selectJoinPage(
new Page<OrderDto>(2, 10),
OrderDto.class,
new MPJLambdaWrapper<Order>()
.selectAll(Order.class)
.select(Product::getUnitPrice)
.selectAs(User::getName, OrderDto::getUserName)
.selectAs(Product::getName, OrderDto::getProductName)
.leftJoin(User.class, User::getId, Order::getUserId)
.leftJoin(Product.class, Product::getId, Order::getProductId)
.orderByAsc(Order::getId));
orderPage.getRecords().forEach(System.out::println);
}The generated SQL includes a LIMIT clause, confirming that pagination works as expected.
Conclusion – The MPJ library provides a practical and concise way to perform join queries in MyBatis‑Plus projects, especially for scenarios that are not overly complex, greatly improving development efficiency. Some issues remain in the current version, and the author hopes future releases will address them.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.