mybatis plus中使用in动态sql的踩坑记录
背景
项目中有个需求,根据多个整型id查询对应的信息
理论上最终sql应该是如下所示:
select userName form t_user where userId in(1,2,3,4,5,6);
踩坑
但前端传来的参数
Integer[] userIdArr
想着就把userIdArr转成1,2,3,4,5,6就行了
/** * [1,2,3] to 1,2,3 * * @return public static String intArrToString(Integer[] arr) { return StringUtils.join(arr, ","); }
然后将字符串形式的userArrIds作为参数传给mappe,于是写成动态sql如下
@Select("select userName from t_user where userId in (#{userArrIds})") List<String> getUserNameByUserIds(String userArrIds);
按照预想的,它应该生成如下sql语句
select userName form t_user where userId in(1,2,3,4,5,6);
自测一下,发现无论userIdArr传多少个,都只能查出第一个,郁闷了半天
才发现被自己“蠢哭了”,因为将Integer[] userIdArr转换成了String,最终的sql其实是这样的
select userName form t_user where userId in('1,2,3,4,5,6');
整个参数被当成了一个完整的字符串
使用QueryWrapper
既然发现了问题,这条路就走不通了,换一个方法实现,还是将Integer[] userIdArr转换成String,这回用com.baomidou.mybatisplus.core.conditions.query.QueryWrapper来生成动态sql
List<UserDo> userList = userMapper.selectList(new QueryWrapper<UserDo>().inSql("userID",result).select("userName"));
这样结果是查出来了,但也有个问题,因为在定义BaseMapper的时候项目组已经约定了泛型为UserDo,所以用QueryWrapper查询返回值只能是UserDo的列表或单行,如果我需要其他想要的类型都只能通过额外的转换。
@Repository public interface UserMapper extends BaseMapper<UserDo> { ………………………… }
比如我这只需要返回一个List<userName>,拿到数据后还需要转换一下,虽然转换并不难,但还是觉得有点多余。
List<String> userNameList = userDoList.stream().map(UserDo::getuserName).collect(Collectors.toList());
@Select+script
鉴于上面的方法存在两个不优雅的问题
- 需要将整形数组参数转换成字符串
- 返回结果需要二次转换
查阅了很多资料后,发现一个更好的实现方法,既不需要转换入参,也可以按自己的需求决定返回值。
@Select("<script> " + "select userNanme from t_user where userId " + "in <foreach item='item' index='index' collection='userIdArr' open='(' separator=',' close=')'> #{item} </foreach> " + "</script>") List<String> getUserNameByUserIds(Integer[] userIdArr);