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,所以導致了空指針。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM