mybatis 多字段in_mybatis框架下select带in批量查询,返回结果集无序问题

引言

在实际项目中有的时候会多次连接数据库查询,有的时候会带上in的语句,在二次查询的时候返回的数据集就是没有顺序的。比如我们在微博平台上搜索某个用户,为了搜索速度够快,在els那边一般只存user的id和username。当根据username匹配到用户,获取到id后,还会在本地的数据库中根据id去查询用户更多的信息,比如sex,signature等字段。在第一次查询的时候是按照username匹配程度来排序的,而第二次查询的结果希望能与第一次查询的结果顺序保持一致。

因此,如何保证in查询的结果与输入的一致是非常重要的。

实操

一. 辟谣

有人说只要把resultType中的HashMap转换成LinkedHaspMap,就可以保持一致(网址:https://blog.csdn.net/qq_29115715/article/details/69958264)

经过博主亲自尝试,此种方法根本就无效!!

二. 利用sql原声语句

先来看一下普通的in语句出现的效果

图1.普通的in语句

利用order by field的效果

图2.利用order by field的效果

因此,利用mybatis的mapper.xml编写原生的xml也可以达到如此效果,代码如下:

接口层

@Repository

@Mapper

public interface UserMapper extends BaseDao {

List yktestOrder(@Param("ids")List ids);

}

Mapper.xml

select

u.id,

u.username

FROM

user u

WHERE

1 = 1

AND u.id IN

#{item}

order by field(u.id,

#{item}

)

测试controller

@Autowired

private UserMapper userMapper;

@PostMapping(value = "/yktest")

@ResponseBody

public RestResponse yktest() throws Exception {

List ids = new ArrayList(){{

this.add(635L);

this.add(1L);

this.add(1179L);

}};

List result1 = userMapper.selectBatchIds(ids);

List resutl2 = userMapper.yktestOrder(ids);

System.out.println("result1");

result1.forEach(System.out::println);

System.out.println("result2");

resutl2.forEach(System.out::println);

return RestResponse.ok("执行完成");

}

最终的console输出的结果如下:

图3.测试结果图

注意:特别要小心xml中order by field的括号写法

三. 自己编写utils方法进行转换

思路

传入的对象是一个list或者是一个list>类型。我们知道User继承Object,但是List并不继承List。所以我们只能拿Object去接收待转顺序的结果集Object result,并且我们要知道该结果集的类型Class> resultClass

同理,我们要知道待排序的list和它的类型分别为Object order,Class> orderClass。以及我们还要知道根据结果集result中哪个字段进行排序,String orderName

接着我们转换顺序的思想就是,拿一个中间的tempMap,类型为Map。先遍历result,拿到每个元素的orderName的值当做tempMap的key,每个元素自身当做value。然后我们在遍历order,把其中的每个元素从temp的map之中get出来,放到最终的结果List returnList之中。

最后把 returnList返回。因为我们知道查询结果都是List<>类型的,所以才可以确定返回的就是要List。

PS:有几个点需要注意一下:

map取key值的方法就是get("id"),而如果是User对象取值方式是getId()。所以二者需要做类型区别判断。

order之中可能存在一些id,在result之中并不存在,所以最后的从temp的map之中取元素的时候要做取到结果是否为空的判断。

一句话概括就是用map作为中间变量,先把所有元素存进去,然后按照预想的顺序get出来add到返回的list中。

最终代码如下:

/**

* 传入相应的查询结果和欲想顺序进行顺序重排

*

* @param result 传入的查询结果

* @param resultClass 传入查询结果的类

* @param order 传入的顺序List

* @param orderClass 传入的顺序List的类型

* @param orderName 传入的要排序的字段名

* @param

* @param

* @return

* @throws Exception

*/

public static List changeResultOrder(Object result, Class> resultClass,

Object order, Class> orderClass, String orderName) {

List returnList = new ArrayList<>();

Map tempMap = new HashMap<>();

for (resultClass aoo : (List) result) {

if (resultClass.isAssignableFrom(Map.class)) {

Object b = MapUtils.getObject((Map) aoo, orderName);

orderClass cb = (orderClass) b;

if (orderClass.isAssignableFrom(Long.class)) {

cb = (orderClass) Long.valueOf(b + "");

}

tempMap.put(cb, aoo);

} else {

try {

Method method = aoo.getClass().getMethod("get" + toUpperFirstChar(orderName));

orderClass b = (orderClass) method.invoke(aoo);

tempMap.put(b, aoo);

}catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e){

throw new FantuanRuntimeException("调用sqlHelpUtils出错,反射获取方法有误",e);

}

}

}

for (orderClass boo : (List) order) {

resultClass getResult = tempMap.get(boo);

if (null != getResult){

returnList.add(getResult);

}

}

return returnList;

}

总结

个人比较推荐使用方法三,一是比较灵活,二是我们在用mybatis的时候很多时候会用mybatis的插件,不常在底层操作mapper.xml文件。正如博主在代码中用的

com.baomidou

mybatis-plus

2.1.9

在查询的时候就直接用

List selectBatchIds(@Param("coll") Collection extends Serializable> idList);

此时用自己编写的代码去调整顺序就非常合适。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值