众所周知,Mybatis Plus 封装的 mapper 不支持 join,如果需要支持就必须自己去实现。但是对于大部分的业务场景来说,都需要多表 join,要不然就没必要采用关系型数据库了。
直到前几天,偶然碰到了这么一款叫做mybatis-plus-join
的工具(后面就简称mpj
了),使用了一下,不得不说真香!彻底将我从xml地狱中解放了出来,终于可以以类似mybatis-plus
中QueryWrapper
的方式来进行联表查询了,话不多说,我们下面开始体验。
引入依赖
首先在项目中引入引入依赖坐标,因为mpj
中依赖较高版本mybatis-plus
中的一些api,所以项目建议直接使用高版本。
- maven
<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>
引入相关依赖后,在springboot
项目中,像往常一样正常配置数据源连接信息就可以了。
- Gradle
implementation 'com.github.yulichang:mybatis-plus-join-boot-starter:1.4.4'
使用
- mapper继承MPJBaseMapper (必选)
- service继承MPJBaseService (可选)
- serviceImpl继承MPJBaseServiceImpl (可选)
核心类MPJLambdaWrapper和MPJQueryWrapper
MPJLambdaWrapper用法
简单的三表查询
class test {
@Resource
private UserMapper userMapper;
void testJoin() {
//和Mybatis plus一致,MPJLambdaWrapper的泛型必须是主表的泛型,并且要用主表的Mapper来调用
MPJLambdaWrapper<UserDO> wrapper = new MPJLambdaWrapper<UserDO>()
.selectAll(UserDO.class)//查询user表全部字段
.select(UserAddressDO::getTel)//查询user_address tel 字段
.selectAs(UserAddressDO::getAddress, UserDTO::getUserAddress)//别名 t.address AS userAddress
.select(AreaDO::getProvince, AreaDO::getCity)
.leftJoin(UserAddressDO.class, UserAddressDO::getUserId, UserDO::getId)
.leftJoin(AreaDO.class, AreaDO::getId, UserAddressDO::getAreaId)
.eq(UserDO::getId, 1)
.like(UserAddressDO::getTel, "1")
.gt(UserDO::getId, 5);
//连表查询 返回自定义ResultType
List<UserDTO> list = userMapper.selectJoinList(UserDTO.class, wrapper);
//分页查询 (需要启用 mybatis plus 分页插件)
Page<UserDTO> listPage = userMapper.selectJoinPage(new Page<>(2, 10), UserDTO.class, wrapper);
}
}
对应sql
SELECT
t.id, t.name, t.sex, t.head_img,
t1.tel, t1.address AS userAddress,
t2.province, t2.city
FROM
user t
LEFT JOIN user_address t1 ON t1.user_id = t.id
LEFT JOIN area t2 ON t2.id = t1.area_id
WHERE (
t.id = ?
AND t1.tel LIKE ?
AND t.id > ?)
说明:
- UserDTO.class 查询结果返回类(resultType)
- selectAll() 查询指定实体类的全部字段
- select() 查询指定的字段,支持可变参数,同一个select只能查询相同表的字段
- selectAs() 字段别名查询,用于数据库字段与业务实体类属性名不一致时使用
- leftJoin() 参数说明;第一个参数: 参与连表的实体类class 第二个参数: 连表的ON字段,这个属性必须是第一个参数实体类的属性 第三个参数: 参与连表的ON的另一个实体类属性
- 默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3…
- 条件查询,可以查询主表以及参与连接的所有表的字段,全部调用mp原生的方法,正常使用没有sql注入风险
MPJLambdaWrapper 还有很多其他的功能
- 简单的SQL函数使用:
https://gitee.com/best_handsome/mybatis-plus-join/wikis/selectFunc()?sort_id=4082479
- ON语句多条件支持:
https://gitee.com/best_handsome/mybatis-plus-join/wikis/leftJoin?sort_id=3496671
等效于ResultMap
<resultMap id="xxxxxxxx" type="com.github.yulichang.join.dto.UserDTO">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--其他属性省略-->
<collection property="addressList" javaType="java.util.List"
ofType="com.github.yulichang.join.entity.UserAddressDO">
<id property="id" column="mpj_id"/>
<result property="address" column="address"/>
<result property="userId" column="user_id"/>
<!--其他属性省略-->
</collection>
</resultMap>
MPJLambdaWrapper其他功能
- 一对一,一对多使用:https://ylctmh.com/pages/core/lambda/select/selectCollection.html
- 简单的SQL函数使用:https://ylctmh.com/pages/core/lambda/select/selectFunc.html
- ON语句多条件支持:https://ylctmh.com/pages/core/lambda/join/leftJoin.html
分页查询
mpj
中也能很好的支持列表查询中的分页功能,首先我们要在项目中加入分页拦截器:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
接下来改造上面的代码,调用selectJoinPage()
方法:
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);
}
注意在这里需要添加一个分页参数的Page
对象,我们再执行上面的代码,并对日志进行解析,查看sql语句:
可以看到底层通过添加limit
进行了分页,同理,MPJQueryWrapper
也可以这样进行分页。
最后
经过简单的测试,个人感觉mpj
这款工具在联表查询方面还是比较实用的,能更应对项目中不是非常复杂的场景下的sql查询,大大提高我们的生产效率。当然,在项目的issues
中也能看到当前版本中也仍然存在一些问题,希望在后续版本迭代中能继续完善。
关注我,后续更新更多好用的工具,效率天花板