Simplify MyBatis-Plus Join Queries with MPJ: A Hands‑On Guide
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, covering dependency setup, mapper changes, query construction, pagination, and practical code examples.
MyBatis-Plus greatly simplifies database operations in Java projects, but its native join capabilities have long been criticized. The
mybatis-plus-join(MPJ) library eliminates the need to write XML for left or right joins, allowing developers to write join queries in a fluent, type‑safe style.
Introduce Dependency
Add the following Maven dependencies to your project. MPJ requires a recent version of MyBatis‑Plus, so using the latest versions is recommended.
<code><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>
</code>Configure the data source in the usual Spring Boot way after adding the dependencies.
Data Preparation
Create three tables for testing join queries: an order table, a user table (containing user names), and a product table (containing product names and unit prices). The order table references the user and product tables by their IDs.
Modify Mapper
Replace the default
BaseMapperinheritance with
MPJBaseMapperfor each entity mapper. For example:
<code>@Mapper
public interface OrderMapper extends MPJBaseMapper<Order> {
}
</code>The same change applies to the mappers of the other two tables. Services can optionally extend
MPJBaseServiceand
MPJBaseServiceImpl, but this is not required.
Query with MPJLambdaWrapper
Inject the
OrderMapperinto a service and use
selectJoinListto perform a join without writing SQL:
<code>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);
}
</code>The result shows fields from the related tables correctly:
The
MPJLambdaWrapperprovides several useful methods:
selectAll(): select all columns of the specified entity.
select(): select specific columns (only from the same table in a single call).
selectAs(): alias a column to match a DTO field name.
leftJoin(): perform a left join, specifying the target entity, the ON field from the target, and the ON field from the source.
MPJQueryWrapper
The
MPJQueryWrapperoffers a string‑based alternative similar to MyBatis‑Plus
QueryWrapper. The same query can be written as:
<code>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);
}
</code>When using the string version, refer to the generated table aliases (
tfor the main table,
t1,
t2, …) instead of the original table names.
Pagination Query
MPJ also supports pagination. First, register the MyBatis‑Plus pagination interceptor:
<code>@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
</code>Then use
selectJoinPage:
<code>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);
}
</code>The generated SQL includes a
LIMITclause for pagination:
Conclusion
MPJ provides a practical solution for join queries in MyBatis‑Plus projects, especially when the query logic is not overly complex. It reduces the need for manual XML, improves development efficiency, and integrates smoothly with existing MyBatis‑Plus features such as pagination.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.