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下的多表连表查询了。