mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了

这篇具有很好参考价值的文章主要介绍了mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引子

先看个技术题吧。

下面两段代码,执行testFoo,结果分别是什么?

@Test
public void testFoo() {
    foo(Arrays.asList(1, 2, 3));
}

void foo(Object... args) {
    System.out.println(args);
}
@Test
public void testFoo() {
    foo(Arrays.asList(1, 2, 3));
}

void foo(Object... args) {
    System.out.println(args);
}
void foo(List list){
    System.out.println(list);
}

 文章来源地址https://www.toymoban.com/news/detail-622451.html

一眼看出来结果的同学,恭喜你,本文内容可以略过。

 

下面是正文。

 

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>接口中定义。

mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了

 

 下面是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);

}


单从方法签名以及清晰的javadoc注释,我们可以看到,in方法接收字段值的方式有两种,一种是Object...,一种是Collection<?>。
■ Collection<?>不用说了,是集合,比如List<E>、Set<E>、Queuet<E>等。
■ Object...是可变长参数(可变参数),可变长参数本质上就是一个数组,既可以接收一个或多个离散的值,也可以接收数组对象。
也就是说,in方法同时支持传入数组和集合。当我们入参是List时,调用的是重载的in(Collection<?>),其他入参方式则是调用重载的in(Object...)。由此看来,调用mybatis-plus的in时,是传Array还是传List?就见分晓了。

现在,我们来做一个假设:假设这些in重载方法里没有in(Collection<?>),只有in(Object...),那么,我们应用程序在调用的时候,当需要in的参数值是一个集合时,如果我们把集合直接传给in(Object...),那就是bug。因为在可变长参数里,集合是作为一个参数值的(不是多个)。也就是说,在这种假设下,程序生成的SQL会是 SELECT * FROM table1 WHERE state IN ('[SUCCESS,FAIL]') ,我们的程序为规避这个bug,就要先把集合转换为数组再调用in(Object...)。显然,这样会给我们的开发带来额外的工作,更糟糕的是,这样的bug很难彻底规避。

mybatis-plus框架的研发团队显然意识到了这个“假设”,故而增加了重载的in(Collection<?>),毋庸置疑是非常优秀的设计。

下面详细列举使用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里的参数值:

mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了

 

 

🍀错误姿势二:

.in(StringUtils.isNotBlank(vo.getOrderNumList()),ScbgOrder::getOrderNo,"123,4566");

 错误结果二:

==> Preparing: SELECT * FROM emax_scbg_order WHERE order_no IN (?)
==> Parameters: 123,4566(String)
<== Total: 0

OK,那么not in怎么用呢?

在mybatisplus中,not in的用法与in是相同的。如下notIn方法签名的截图一看便知:

mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了

话外:调用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,所以导致了空指针。

话外:对比spring-data-redis,再次表扬一下mybatisplus这些优秀的in重载

spring-data-redis中的RedisTemplate类,提供了两个execute方法,用来允许我们执行LUA脚本。注意到了吧?这2个execute最后那个参数的类型是Object...。所以,在使用时,小心掉坑里,千万别直接传List哦。

mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了

 

EOF,感谢阅读!

到了这里,关于mybatis-plus中的in的使用,是传Array?还是传List?别再纠结了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringBoot】MyBatis与MyBatis-Plus分页查询 & github中的PageHelper

            笔者写这篇博客是因为近期遇到的关于两者之间的分页代码差距,其实之前也遇见过但是没有去整理这篇博客,但由于还是被困扰了小一会儿时间,所以还是需要 加深记忆 。其实会看前后端传参解决这个问题很快、不麻烦。关于这两个框架的分页代码问题主要就

    2024年02月03日
    浏览(37)
  • Mybatis-plus中的DML编程控制--增删改的高级操作

    1.1、id生成策略控制 不同的表应用不同的id生成策略 日志:自增(1,2,3,4,…) 购物订单:特殊规则( FQ23948AK3843) 外卖单:关联地区日期等信息(10 04 20200314 34 91) 关系表:可省略id ······ 名称: @TableId 类型: 属性注解 位置:模型类中用于表示主键的属性定义上方 作用:设置当前类中主

    2024年02月16日
    浏览(28)
  • MyBatis-plus中的两种快捷操作数据库方式:1、mapper调用 2、ActiveRecord方式(简称AR) 二者的使用和区别介绍

            在使用MyBatis操作数据库时,需要频繁的写mapper层dao接口以及对应的配置文件和SQL语句,当功能方法繁杂,业务逻辑不复杂的时候,我们可以使用MyBatis的升级版MyBatis-Plus来代替我们写这些繁琐的配置文件和简单的SQL。 (1)书写或使用MP生成数据库表对应的实体类。

    2024年02月07日
    浏览(31)
  • 【MyBatis-Plus】MyBatis进阶使用

    目录 一、MyBatis-Plus简介 1.1 介绍 1.2 优点 1.3 结构 二、MyBatis-Plus基本使用 2.1 配置 2.2 代码生成 2.3 CRUD接口测试 三、MyBatis-Plus策略详解 3.1 主键生成策略 3.2 雪花ID生成器 3.3 字段自动填充策略 3.4 逻辑删除 四、MyBatis-Plus插件使用 4.1 乐观锁插件 4.1.1 什么是乐观锁和悲观锁? 4.

    2024年02月04日
    浏览(37)
  • MyBatis-Plus中的更新操作(通过id更新和条件更新)

    目录 前言 一、通过id更新 二、条件更新 2.1 使用QueryWrapper进行条件更新 2.2 使用UpdateWrapper进行条件更新 总结  本文学习MP中的更新操作方法,带大家一起查看源码,了解更新操作的方法。学会熟练地去运用更新方法解决自己在项目中的问题。 Mybatis-Plus知识点[MyBatis+MyBatis-Pl

    2024年02月06日
    浏览(32)
  • Mybatis-plus 使用

            mybatis-plus提供了 ·@TableName·, @TableId, @TableField, @TableLogic 四种注解,其含义分别为:  @TableName          @TableName(\\\"SPF_Require_Vehicle\\\")    用于声明当前class所对应数据库中的表,如果class的名字和表的名字完全相同,则不需要添加该注解,如果不一样,则需要用该注解进

    2024年02月07日
    浏览(32)
  • mybatis-plus分页total为0,分页失效,mybatis-plus多租户插件使用

    背景:项目使用mybatis分页插件不生效,以及多租户使用时读取配置异常 多租户插件使用遇到的问题: 最开始在MyTenantLineHandler中使用 @Value(\\\"${tables}\\\"),服务启动时能从配置中心拉取到配置,但在运行时获取到的值为空,试了很多方法都不生效,后面将配置中心的配置在调用My

    2024年02月06日
    浏览(37)
  • 关于mybatis-plus中Ipage 、page 和pageUtils中的区别

         在使用人人开源框架的时候,通过逆向工程自动生成了分页功能,然而在使用的时候经常被关于Ipage和page等对象搞混,所以记录这篇文章用来介绍之间的区别 可以看见上面就是逆向工程帮忙生成的分页方法 里面出现了三个对象 pageUtils、page和Ipage 先来将pageUtils吧,pag

    2024年02月04日
    浏览(27)
  • Mybatis-plus的使用

    Mybatis-plus的使用 一、简介 Mybatis-plus的基于mybatis的,简化了单表mybatis的操作。 注意:它并没有提升性能,只是简化了开发过程。 二、在springboot中的基本使用 1、导入依赖 2、添加相应的数据库配置(application.properties) 3、在Application类上添加dao接口的路径扫描 4、编写实体类

    2024年02月09日
    浏览(29)
  • Mybatis-Plus使用方法

    MyBatis-Plus 提供了丰富的增强版的 CRUD 方法,使得开发者能够更简洁、高效地进行数据库操作。以下是如何使用 MyBatis-Plus 自带的增强版 CRUD 方法的基本步骤: 添加依赖 首先,确保你的 Maven 项目中已经添加了 MyBatis-Plus 的相关依赖,包括核心依赖和数据库驱动依赖。 xml复制代

    2024年04月11日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包