Mybatis-Plus中复杂连表的查询

5,506 阅读2分钟

mybatis-plus在单表查询时非常方便,比如分页插件、链式查询条件、基于条件的查询条件叠加等特性,都对开发查询业务十分友好。
但是涉及复杂连表的时候,mybatis-plus就不是很方便了,往往需要自己写原生的mybatis-xml那套,譬如分页、查询条件之类的都要自己实现,这种混合的模式十分难受。
最近发现mybatis-plus的特性也能在复杂连表中使用,但是看起来没那么优雅,不过好处也是有的。

普通mybatis-plus场景下的几个查询代码优势

链式查询条件

   sysPolicyBelongMapper.selectList(Wrappers.<SysPolicyBelong>lambdaQuery()
              .eq(SysPolicyBelong::getBelongType, policyBelong.getName())
              .eq(SysPolicyBelong::getBelongId, belongId)
              .or(i->i.eq(SysPolicyBelong::getEnable,false)));
          

可以方便地集成单表的多查询条件

基于条件的查询条件叠加

一个常见的场景,列表分页查询接口,会有很多搜索参数,但是传空或不传时,需要不叠加这个搜索条件,仅在有值的时候才要加上这个查询条件,传统的mybatis下,一般需要这样写:

if(StringUtils.isNotBlank(name)){
  params.add("name",name);
}
if(roleId !=null){
  params.add("roleId",roleId);
}

mybatis-plus中可以这样直接在链式查询条件中叠加此条件,条件为false时,此条查询条件不会添加到最终的查询语句。

Wrappers.<SysUser>lambdaQuery()
   .like(StringUtils.isNotBlank(name), SysUser::getName, name)
   .eq(roleId != null, SysUser::getRoleId, roleId);

分页查询

Page<SysUser> iPage = new Page<>(page, pageSize);
IPage<UserListDto> userListDtoPage = sysUserMapper.selectUserPageList(iPage, wrapper);
// 分页数据
userListDtoPage.getRecords();
// 总记录数
userListDtoPage.getTotal();

除了方便外,mybatis-plus的分页插件是在当页无数据时是仅作count查询的。

复杂连表sql的mybatis-plus实现

mybatis-plus自带的方法是很难实现复杂sql查询的,这里如果我们还想用上面提到的几个特性,就要使用mybatis-plus提供的自定义sql功能: 大致理念是在service层集成好QueryWrapper对象,之后传递到mapper接口或者mapper.xml文件中。 首先看一下mapper接口和mapper.xml文件,两种方式都是可以的
纯mapper接口

String SELECT_SQL = " select user.id                         as userId,
               IFNULL(so.name, '-')                        as platform,
               user.username                               as username,
               user.enable                                 as enable,
               IFNULL(GROUP_CONCAT(DISTINCT sg.name), '-') as groupNames,
               IFNULL(GROUP_CONCAT(DISTINCT sp.name), '-') as policyNames,
               user.email  as email,
               user.phone  as phone
        from sys_user user
                 left join sys_organization so on so.id = user.organization_id
                 left join sys_user_group sug on user.id = sug.user_id
                 left join sys_group sg on sug.group_id = sg.id
                 left join sys_policy_belong spb on spb.belong_id = user.id and spb.belong_type = 'user'
                 left join sys_policy sp on sp.id = spb.policy_id
            ${ew.customSqlSegment}
        group by user.id";

@Select(SELECT_SQL)
IPage<UserListDto> selectUserPageList(Page<SysUser> page, @Param(Constants.WRAPPER) QueryWrapper<SysUser> wrapper);

@Select(SELECT_SQL)
List<UserListDto> selectUserList(@Param(Constants.WRAPPER) QueryWrapper<SysUser> wrapper);
     
 

mapper.xml模式:

IPage<UserListDto> selectUserPageList(Page<SysUser> page,
                     @Param(Constants.WRAPPER) QueryWrapper<SysUser> wrapper);

<select id="selectUserPageList" resultType="com.wochanye.dtube.rbac.bean.user.UserListDto">
            select user.id                         as userId,
           IFNULL(so.name, '-')                        as platform,
           user.username                               as username,
           user.enable                                 as enable,
           IFNULL(GROUP_CONCAT(DISTINCT sg.name), '-') as groupNames,
           IFNULL(GROUP_CONCAT(DISTINCT sp.name), '-') as policyNames,
           user.email  as email,
           user.phone  as phone
    from sys_user user
             left join sys_organization so on so.id = user.organization_id
             left join sys_user_group sug on user.id = sug.user_id
             left join sys_group sg on sug.group_id = sg.id
             left join sys_policy_belong spb on spb.belong_id = user.id and spb.belong_type = 'user'
             left join sys_policy sp on sp.id = spb.policy_id
        ${ew.customSqlSegment}
    group by user.id
</select>

这里需要注意的是两点:
1.每个表都需要设置别名
2.where语区不写,用${ew.customSqlSegment}代替
这里可以看出来,分页功能也是不需要自己单独写的,将Page类传递过来就可以。
之后在service层组装QueryWrapper,这时候就没法用Lambda模式了,只能使用原生的模式:

QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>();
// 这里的user、so、sg对应sql中的表别名
queryWrapper.eq("user.deleted", false)
            .in("user.organization_id", isOrganizationManager)
            .eq("user.create_user", userId)
            .eq("so.name", organizationName)
            .eq("sg.name",groupName);
Page<SysUser> iPage = new Page<>(pageParam.getPage(), pageParam.getPageSize());
IPage<UserListDto> userListDtoPage = sysUserExtMapper.selectUserPageList(iPage, queryWrapper);

这样就可以实现mybatis-plus下的多表连表查询了。