源码解读Mybatis List列表In查询实现的注意事项

在SQL开发过程中,动态构建In集合条件查询是比较常见的用法,在Mybatis中提供了foreach功能,该功能比较强大,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。下面是一个演示示例:

  <select id="findByIdsMap" resultMap="BaseResultMap">
    Select
    <include refid="Base_Column_List" />
     from jria where ID in
     <foreach item="item" index="index" collection="list" 
                    open="(" separator="," close=")">
                   #{item}
            </foreach>
 </select> 

但由于官方文档对这块的使用,描述的比较简短,细节上也被忽略掉了(可能是开源项目文档一贯的问题吧),也使用不少同学在使用中遇到了问题。特别是foreach这个函数中,collection属性做什么用,有什么注意事项。由于文档不全,这块只能通过源代码剖析的方式来分析一下各个属性的相关要求。

collection属性的用途是接收输入的数组或是List接口实现。但对于其名称的要求,Mybatis在实现中还是有点不好理解的,所以需要特别注意这一点。

下面开始分析源代码(笔记使用的是Mybatis 3.0.5版本)

先找到Mybatis执行SQL配置解析的入口

MapperMethod.java类中 public Object execute(Object[] args) 该方法是执行的入口.

针对 in 集合查询,对应用就是  selectForList SelctForMap 方法。

 

但不管调用哪个方法,都会对原来JDK传入的参数 Object[]类型,通过 getParam方法转换成一个Object,那这个方法是做什么的呢?分析源码如下:

 

上图中标红的两处,很惊讶的发现,一个参数与多个参数的处理方式是不同的(后续很多同学遇到的问题,就有一大部分出自这个地方)。如果参数个数大于一个,则会被封装成Map, key值如果使用了Mybatis的 Param注解,则会使用该key值,否则默认统一使用数据序号,从1开始。这个问题先记下,继续分析代码,接下来如果是selectForList操作(其它操作就对应用相应方法),会调用DefaultSqlSession的public List selectList(String statement, Object parameter, RowBounds rowBounds) 方法

又一个发现,见源代码如下:

 

上图标红部分,对参数又做了一次封装,我们看一下代码

 

 

现在有点清楚了,如果参数类型是List,则必须在collecion中指定为list, 如果是数据组,则必须在collection属性中指定为 array.

现在就问题就比较清楚了,如果是一个参数的话,collection的值取决于你的参数类型。

如果是多个值的话,除非使用注解Param指定,否则都是数字开头,所以在collection中指定什么值都是无用的。下图是debug显示结果。

 

针对上面分析的结果,下面给出了一个使用的解决方案,希望对大家对帮助。

在使用这个功能是需要特别注意以下规则:
1. 当查询的参数只有一个时 
  findByIds(List<Long> ids)
 1.a 如果参数的类型是List, 则在使用时,collection属性要必须指定为 list
 <select id="findByIdsMap" resultMap="BaseResultMap">
         Select
         <include refid="Base_Column_List" />
         from jria where ID in
                  <foreach item="item" index="index" collection="list" 
                         open="(" separator="," close=")">
                        #{item}
                </foreach>
  </select> 
 
 findByIds(Long[] ids)
 1.b 如果参数的类型是Array,则在使用时,collection属性要必须指定为 array
  <select id="findByIdsMap" resultMap="BaseResultMap">
                 select
                 <include refid="Base_Column_List" />
          from jria where ID in
                  <foreach item="item" index="index" collection="array" 
                         open="(" separator="," close=")">
                        #{item}
                </foreach>
  </select> 
 
2. 当查询的参数有多个时,例如 findByIds(String name, Long[] ids)
 这种情况需要特别注意,在传参数时,一定要改用Map方式, 这样在collection属性可以指定名称
         下面是一个示例
         Map<String, Object> params = new HashMap<String, Object>(2);
        params.put("name", name);
         params.put("ids", ids);
        mapper.findByIdsMap(params);
 
 <select id="findByIdsMap" resultMap="BaseResultMap">
                 select
                 <include refid="Base_Column_List" />
          from jria where ID in
                  <foreach item="item" index="index" collection="ids" 
                         open="(" separator="," close=")">
                        #{item}
                </foreach>
   </select> 
 
 
完整的示例如下:
例如有一个查询功能,Mapper接口文件定义如下方法:
List<Jria> findByIds(Long... ids);
使用 in 查询的sql拼装方法如下:
 <select id="findbyIds" resultMap="BaseResultMap">
                 select
                 <include refid="Base_Column_List" />
          from jria where ID in
                  <foreach item="item" index="index" collection="array" 
                         open="(" separator="," close=")">
                        #{item}
                </foreach>
  </select> 
 

Good Luck!
Yours Matthew!

转自:http://yingbin920.iteye.com/blog/1892486
2019-03-13 23:34

开源项目

知识点

相关教程

更多

mahout0.9注意事项SlopeOneRecommender

1、今天试验SlopeOne推荐算法,结果没有提示。心想是不是少了jar包,查查不少。通过网络查询定位此类所在的位置为:org.apache.mahout.cf.taste.impl.recommender.slopeone.包下面,所以去查看jar包,发现没有。查看src包也没有这个类的源码,之后去官网查看,一看,才知道这个算法已被移除了在0.9上。如果想用的话需要0.8.    1 Febru

iOS客户端接入微信SDK回话和朋友圈注意事项

接入微信官网入手指南:http://open.weixin.qq.com/document/gettingstart/ios/; 其实已经很详细了,下面我简单笔记下注意事项: 1.如果“URL scheme”为你所注册的应用程序id 未添加,会导致完成发送时"返回(NULL)",而且不会自动退出微信客户端;因为配置了应用ID,微信内部会自动退出程序; 2.官方微信SDK Sam

Twitter Storm中Bolt消息传递路径之源码解读

本文初次发表于storm-cn的google groups中,现以blog的方式再次发表,表明本人徽沪一郎确实读过这些代码,:). Bolt作为task被executor执行,而executor是一个个的线程,所以executor必须存在于具体的process之中,而这个process就是worker。至于worker是如何被supervisor创建,尔后worker又如何创建executor线程

hibernate list查询 报类型转换异常

查询方法如下:  public List<T> find(String hql, Object... param) {  Query q = this.getCurrentSession().createQuery(hql);  if (param != null && param.length > 0) {  for (int i = 0; i < par

Python 列表(list)操作

列表就像java里的collection,所具有的特性也要比元组更多,更灵活,其character总结如下:
任意对象的有序集合;可通过偏移存取,注意,列表中的元素都是可变的,这是不同于元组的;
长度可变,支持嵌套;还有一些类似java的对象引用机制

升级到 solr 1.4 的注意事项

原文出处:http://blog.chenlb.com/2009/12/update-to-solr-1-4-matter.html    Solr 1.4 已经正式发布一段时间了,是考虑升级的时候了。记录下我目前环境的情况以及注意事项。 Solr 1.4 比较吸引人的有两功能:一是 Trie 的字段支持高性能的 range query,快10倍;二是 solr replication。 目前扩展

Hadoop集群目录配置与注意事项

一、目录配置参数说明 二、注意事项: 1、与mapred.local.dir相关的参数 * mapred.local.dir.minspacestart:在mapreduce运行任务之前,检查temporary 目录下是否还有该选项配置的空闲空间,如果少于该配置,则map或reduce task不会分配到该TaskTracker上,以避免由于磁盘空间不足导致的task失败。默认设置为0,disab

sunspot mongo search 步骤和注意事项

前引:sunspot 类似thiking_sphinx的一个搜索的gem ,它是基于Solr搜索! (它支持的rails 版本是3.0以上) 我做的一个测试项目步骤和注意事项! 1、添加它的gem gem 'sunspot_rails' gem 'sunspot_solr' 如果bundle install 报错误,就这样写 gem 'sunspot_rails', :git => 'htt

Hadoop命令distcp注意事项

Hadoop distcp命令用于在两个不同的集群间拷贝数据,它的优点在于将数据拷贝操作作为mapred程序来执行,这样就大大提高了拷贝的速度,使用distcp命令时必须注意以下事项:    1)数据源集群 的所有节点必须 知道目标集群所有节点ip和host的转换关系 2)目标路径必须存在 3)命令中必须使用主机名,而不是ip地址 测试结果如下:          bin/hadoopdistcp

Storm中Spout使用注意事项小结

Storm中Spout用于读取并向计算拓扑中发送数据源,最近在调试一个topology时遇到了系统qps低,处理速度达不到要求的问题,经过排查后发现是由于对Spout的使用模式不当导致的多线程同步等待。这里罗列几点个人觉得编写Spout代码时需要特别注意的地方: 1. 最常用的模式是使用一个线程安全的queue,如BlockingQueue,spout主线程从queue中读取数据;另外的一个或多个

快速了解mybatis

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。MyBatis是被称为一个数据映射和映射需要的类的属性和数据库中的表的列之间的参数和结果。

Solr_stopword相关注意事项

So in Solr, normally we’re used to stopwords just kind of magically working. If you enter a stop word in a query, it’ll just be silently ignored and stripped out (unlike my legacy OPAC, which will giv

微信图片信息发送注意事项

图文信息的发送效果达到最好 总结以下几条: ①微信图文信息推送的时间一般在晚上8~10点左右,一周大概3次(根据自己的情况而定吧,不要过于骚扰关注者)  ②图文信息编辑完成后记得要发到自己手机预览一遍。  ③图文信息一般分为封面+文字;封面图+文字+图的形式。一般来讲图片不要太大,因为很多人都是在无wifi的情况下浏览。  ④图文信息中还要注意图文的排版,自己调整到最佳之后才能群发。  ⑤微信图文

lucene 5.2.1排序注意事项及优化

之前使用lucene 3.6的时候,如果要根据某个字段排序,直接使用就可以了,如: Sort sort =new Sort(new SortField("updateTime",SortField.Type.LONG,true)); 升级到lucene 5.2.1的时候,这种方法不地了,要多创建一个NumericDocValuesField。 doc.add(new Numer

Java并发编程总结---Hadoop核心源码实例解读

程序设计需要同步(synchronization),原因: 1)复杂的功能要求的需要使用多线程编程,线程之间存在读写共享变量。 2)读写共享变量(shared mutual variable),JVM的内存模型(Memory model: decide when and how changes made by one thread become visuble to others)受到其它因素干扰

最新教程

更多

java线程状态详解(6种)

java线程类为:java.lang.Thread,其实现java.lang.Runnable接口。 线程在运行过程中有6种状态,分别如下: NEW:初始状态,线程被构建,但是还没有调用start()方法 RUNNABLE:运行状态,Java线程将操作系统中的就绪和运行两种状态统称为“运行状态” BLOCK:阻塞状态,表示线程阻塞

redis从库只读设置-redis集群管理

默认情况下redis数据库充当slave角色时是只读的不能进行写操作,如果写入,会提示以下错误:READONLY You can't write against a read only slave.  127.0.0.1:6382> set k3 111  (error) READONLY You can't write against a read only slave. 如果你要开启从库

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Netty基于流的传输处理

​在TCP/IP的基于流的传输中,接收的数据被存储到套接字接收缓冲器中。不幸的是,基于流的传输的缓冲器不是分组的队列,而是字节的队列。 这意味着,即使将两个消息作为两个独立的数据包发送,操作系统也不会将它们视为两个消息,而只是一组字节(有点悲剧)。 因此,不能保证读的是您在远程定入的行数据

Netty入门实例-使用POJO代替ByteBuf

使用TIME协议的客户端和服务器示例,让它们使用POJO来代替原来的ByteBuf。

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-编写服务器端程序

channelRead()处理程序方法实现如下

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

电商平台数据库设计

电商平台数据库表设计:商品分类表、商品信息表、品牌表、商品属性表、商品属性扩展表、规格表、规格扩展表

HttpClient 上传文件

我们使用MultipartEntityBuilder创建一个HttpEntity。 当创建构建器时,添加一个二进制体 - 包含将要上传的文件以及一个文本正文。 接下来,使用RequestBuilder创建一个HTTP请求,并分配先前创建的HttpEntity。

MongoDB常用命令

查看当前使用的数据库    > db    test  切换数据库   > use foobar    switched to db foobar  插入文档    > post={"title":"领悟书生","content":"这是一个分享教程的网站","date":new

快速了解MongoDB【基本概念与体系结构】

什么是MongoDB MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

windows系统安装MongoDB

安装 下载MongoDB的安装包:mongodb-win32-x86_64-2008plus-ssl-3.2.10-signed.msi,按照提示步骤安装即可。 安装完成后,软件会安装在C:\Program Files\MongoDB 目录中 我们要启动的服务程序就是C:\Program Files\MongoDB\Server\3.2\bin目录下的mongod.exe,为了方便我们每次启动,我

Spring boot整合MyBatis-Plus 之二:增删改查

基于上一篇springboot整合MyBatis-Plus之后,实现简单的增删改查 创建实体类 添加表注解TableName和主键注解TableId import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baom

分布式ID生成器【snowflake雪花算法】

基于snowflake雪花算法分布式ID生成器 snowflake雪花算法分布式ID生成器几大特点: 41bit的时间戳可以支持该算法使用到2082年 10bit的工作机器id可以支持1024台机器 序列号支持1毫秒产生4096个自增序列id 整体上按照时间自增排序 整个分布式系统内不会产生ID碰撞 每秒能够产生26万ID左右 Twitter的 Snowflake分布式ID生成器的JAVA实现方案