mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了
springboot项目通常配合mybatisplus来做数据CRUD。
我们在查询或更新数据的时候,有时要用到in来过滤数据。比如
SELECT * FROM emax_scbg_order WHERE order_no IN (1305679009380433922,1305405259472830465)
mybatisplus中关于in方法的使用,在传多个字段值的时候,我们经常搞不清是传Array呢还是ArrayList呢?
其实,细心的同学,看一下in方法的定义,就明白了。
mybatisplus中有4个in方法的重载。
所有Wrapper的超类是AbstractWrapper,AbstractWrapper实现了Func<Children, R>接口。in方法主要在Func<Children, R>接口中定义。
下面是Func<Children, R>接口中in方法的4个重载:
//mybatis-plus-core-3.1.2.jar package com.baomidou.mybatisplus.core.conditions.interfaces; /** * 查询条件封装 * * @author hubin miemie HCL * @since 2017-05-26 */ @SuppressWarnings("unchecked") public interface Func<Children, R> extends Serializable { /** * ignore */ default Children in(R column, Collection<?> coll) { return in(true, column, coll); } /** * ignore */ default Children in(R column, Object... values) { return in(true, column, values); } /** * 字段 IN (v0, v1, ...) * <p>例: in("id", 1, 2, 3, 4, 5)</p> * * <li> 如果动态数组为 empty 则不会进行 sql 拼接 </li> * * @param condition 执行条件 * @param column 字段 * @param values 数据数组 * @return children */ default Children in(boolean condition, R column, Object... values) { return in(condition, column, Arrays.stream(Optional.ofNullable(values).orElseGet(() -> new Object[]{})) .collect(toList())); } /** * 字段 IN (value.get(0), value.get(1), ...) * <p>例: in("id", Arrays.asList(1, 2, 3, 4, 5))</p> * * <li> 如果集合为 empty 则不会进行 sql 拼接 </li> * * @param condition 执行条件 * @param column 字段 * @param coll 数据集合 * @return children */ Children in(boolean condition, R column, Collection<?> coll); }
我们可以看到,in方法接收字段值的方式,一种是Object...,一种是Collection<?>。
■ Collection<?>不用说了,是集合,比如Listt<E>、Sett<E>、Queuet<E>等。
■ Object...是可变长参数(可变参数),可变长参数本质上就是一个数组,既可以接收一个或多个离散的值,也可以接收数组对象。
也就是说,in方法同时支持传入数组和集合。取决于你调用哪个重载方法。
使用in的姿势
正确姿势一(List集合):
List<Long> ids = Arrays.asList(122L,23L);; new QueryWrapper<Driver>().lambda().in(Driver::getServiceId,ids);
正确姿势二(数组对象):
Long[] ids={1305679009380433922,1305679009380433922}; LambdaQueryWrapper<Driver> queryWrapper = new QueryWrapper<Driver>().lambda().in(Driver::getServiceId,ids);
正确姿势三(离散值):
new QueryWrapper<Driver>().lambda() .in(Driver::getServiceId,1305679009380433922,1305679009380433922);
正确结果:
==> Preparing: SELECT * FROM emax_scbg_order WHERE order_no IN (?,?) ==> Parameters: 1305679009380433922(String), 1305405259472830465(String) <== Total: 2
千万别传模棱两可的参数,这样jvm会给你意想不到的结果。
错误姿势一:
.in(
StringUtils.isNotBlank(vo.getOrderNumList()),
ScbgOrder::getOrderNo,
StringUtils.isNotBlank(vo.getOrderNumList()) ? vo.getOrderNumList().split(",") : "");
错误结果一:
==> Preparing: SELECT * FROM emax_scbg_order WHERE order_no IN (?)
==> Parameters: [Ljava.lang.String;@3eb6d7a9(String[])
<== Total: 0
调试程序可以看到values里的参数值:
错误姿势二:
.in(StringUtils.isNotBlank(vo.getOrderNumList()),ScbgOrder::getOrderNo,"123,4566");
错误结果二:
==> Preparing: SELECT * FROM emax_scbg_order WHERE order_no IN (?)
==> Parameters: 1,3(String)
<== Total: 0
OK,那么not in怎么用呢?
在mybatisplus中,not in的用法与in是相同的。如下notIn方法签名的截图一看便知:
话外:调用in出现NullPointerException,why?
下面代码执行到第9行时,抛出空指针异常。可以看出来,这个in重载是public Children in(boolean condition, R column, Object... values)。开发同学疑惑:明明这个in的第一个参数判断vo.getOprationType()是否为空了呀,为空就不执行后面的第三个参数了,不为空才会执行后面的逻辑呀。那么,即使vo.getOprationType()为null,也不应该会抛空指针呀!
1 private LambdaQueryWrapper<PayMerchantOpenFlow> getPayMerchantOpenFlowQueryWrapperByVO(PayMerchantOpenFlowDTO vo){ 2 LambdaQueryWrapper<PayMerchantOpenFlow> wrapper = new QueryWrapper<PayMerchantOpenFlow>().lambda() 3 .eq(StringUtils.isNotBlank(vo.getMerchantCode()), PayMerchantOpenFlow::getMerchantCode,vo.getMerchantCode()) 4 .eq(null != vo.getRelationId(), PayMerchantOpenFlow::getRelationId,vo.getRelationId()) 5 .eq(StringUtils.isNotBlank(vo.getStatus()), PayMerchantOpenFlow::getStatus,vo.getStatus()) 6 .eq(StringUtils.isNotBlank(vo.getMerchantName()), PayMerchantOpenFlow::getMerchantName,vo.getMerchantName()) 7 .eq(StringUtils.isNotBlank(vo.getPayChannelCode()), PayMerchantOpenFlow::getPayChannelCode,vo.getPayChannelCode()) 8 .eq(StringUtils.isNotBlank(vo.getPayChannelName()), PayMerchantOpenFlow::getPayChannelName,vo.getPayChannelName()) 9 .in(StringUtils.isNotBlank(vo.getOprationType()), PayMerchantOpenFlow::getOprationType,vo.getOprationType().split(",")) 10 .between(StringUtils.isNoneBlank(vo.getCreateTimeBegin(), vo.getCreateTimeEnd()), PayMerchantOpenFlow::getCreateTime, vo.getCreateTimeBegin() + " 00:00:01", vo.getCreateTimeEnd() + " 23:59:59") 11 .orderByDesc(PayMerchantOpenFlow::getCreateTime); 12 return wrapper; 13 }
答案是:上面的“第一个条件为true时才使用第三个参数执行sql处理”是in方法内部的逻辑,而不是调用方的逻辑。调用方所做的事情是把参数值传给in方法。所以, 当vo.getOprationType()#split时,由于vo.getOprationType()是null,所以导致了空指针。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/17595281.html