我的编程空间,编程开发者的网络收藏夹
学习永远不晚

带你重新认识MyBatis的foreach

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

带你重新认识MyBatis的foreach

用了MyBatis的同行,应该见过foreach,它一般是这样用的:

<select id="foreachTest" resultType="Blog">
    select * from t_blog where id in
    <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

难记

有没有人跟我一样,觉得

<foreach collection="list" index="index" item="item" open="(" separator="," close=")">

这一串很啰嗦?每次写<foreach>都因为记不住和怕记不牢,要查找和复制现有的来改。假如可以简化,就不至于要这样了。
一项项来分析:

  • foreach这个是xml标签,少不了。
  • collection可以通过探测参数类型+数量,从而在大多数情况下,知道对应哪个参数而省略。
  • index这个就更加不用写了,幸好它真的是用时才写,不用不写。
  • item假如缺省值就是item,则可能会有一些冲突,比如某个表名叫item,会不会让人掉坑里才豁然知道缘由?想不清楚。
  • open难道不是通常都是"("吗?但只要不写open,缺省值是没有,即是空串,很无语,强迫我们几乎每个foreach都要写open="("
  • separator难道不是绝大多数都是","吗?缺省值也是空串,更无语
  • closeopen同理。

空集合问题

还有一个问题,当传入的集合是空集的时候,比如上面这个例子,某些情况计算出来的list是空集合。按道理,既然list是id的集合,空集合意味着应该select到0条记录。但结果却是报SQL语法错误。原因是生成的SQL长这样:

select * from t_blog where id in ;      -- 为了明显,我补了个分号

是的,按SQL语法,in后面的小括号是不能没有内容的,小括号本身也是不能省的,抓狂。

在以前,我接触的项目有DAO层(指java interface mapper之上的一层),我会在DAO层先判断,若list是Empty,直接返回空集,否则再执行mybatis的查询。后来的一些项目,推崇简单化,没有DAO层,Service直接调用java interface mapper。把这个“判空返回空”的逻辑写在Service就显得别扭。难道MyBatis就不能优雅地解决这个问题吗?

解法

直到后来看到了这种写法:

<select id="foreachTest" resultType="Blog">
    select * from t_blog
  <where>
    <foreach collection="list" index="index" item="item" open=" id in (" separator="," close=")">
        #{item}
    </foreach>
  </where>
</select>

特别之处在于open="id in (",与一开始的id in写在foreach外面有什么不同呢?经过实验,结论是这样的:

  • 当list非空时,两者并无区别。
  • 当list为空时,既不生成open值,也不生成close值!

所以,当list为空时,SQL就是:select * from t_blog,也就没有违反语法。但是查到的是全部的记录,而不是预期的“0条记录”。
改进为这样写

<select id="foreachTest" resultType="Blog">
    select * from t_blog
  <where>
    1 = 0 
    <foreach collection="list" index="index" item="item" open=" or id in (" separator="," close=")">
        #{item}
    </foreach>
  </where>
</select>

如果,还有其它的and条件,则需要在or的两边加上小括号。

<select id="foreachTest" resultType="Blog">
    select * from t_blog
  <where>
    (1 = 0 
    <foreach collection="list" index="index" item="item" open=" or id in (" separator="," close=")">
        #{item}
    </foreach>
    )
    and ...
  </where>
</select>

这样,不论list是否empty,都会生成正确语法和功能的SQL语句。有兴趣的朋友可自行推导。

优雅的解法

但我觉得上面的写法不够优雅,经过实验,找到一种我认为更优雅的写法:

<select id="foreachTest" resultType="Blog">
    select * from t_blog
  <where>
    <foreach collection="list" index="index" item="item" open=" and id in (" close="-1)">
        #{item},
    </foreach>
    and ...
  </where>
</select>

留意:

  • separator没了,缺省就是空串
  • #{item}后面有了个逗号(,)
  • close里多了个-1

是这样的思路,我们要解决的是in后面是空的问题,假如在list为empty时,也能“塞”入一个不存在的值,比如这里规定id不可能是-1,那么生成的sql就是where id in (-1),语法没错,且查不到数据。而当list非空时,生成的sql如where id in (1,2,3,-1),虽然有-1,但不影响查出来的结果。只是本来3是最后一个,不需要加逗号,由于后面固定有-1,所以每个#{item}后面固定要有逗号,如果逗号放在separator,则只出现在各个id之间,放在#{item}就可以出现在每个item后了。

通过此案例,回头一看,思路一下子就打开了。open里的写法可以很灵活,只要符合SQL语法的,理论上都可以往open里放。separatorclose也一样。可能作者就是因为这些灵活的用法,所以干脆让它们的缺省值是空串。这本无标准,所以不能说这样做就是对或错的。

一种简化<foreach>的设想

但如果允许我修改设计的话,我会让open的缺省值为"("separator的缺省值为", "close的缺省值为")"。因为大多数情况下它们的值就是这样。假如特殊情况下,就想要它的值为空串,可以这么写open="",何尝不可。这样做的好处是,通常情况下foreach会很简洁:

<foreach collection="list" item="item">
    #{item}
</foreach>

例如,像文章开头分析的那样,还可以去掉collection,甚至是item,那成为这样的极简:

<foreach>
    #{item}
</foreach>

整体这样:

<select id="foreachTest" resultType="Blog">
    select * from t_blog where id in
    <foreach>
        #{item}
    </foreach>
</select>

简化成这样,谁还不敢直接写<foreach>了?

总结

本文提出了一种简化<foreach>写法的设想,更重要的是通过解决空集时生成的SQL语法问题,更深刻地理解MyBatis的foreach的生成机制。打开思路,更灵活地利用openseparatorclose,得到符合预期的SQL,还兼顾到代码的优雅。

到此这篇关于重新认识MyBatis的foreach的文章就介绍到这了,更多相关MyBatis的foreach内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

带你重新认识MyBatis的foreach

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

带你重新认识MyBatis的foreach

这篇文章主要介绍了重新认识MyBatis的foreach,本文提出了一种简化<foreach>写法的设想,更重要的是通过解决空集时生成的SQL语法问题,更深刻地理解MyBatis的foreach的生成机制,需要的朋友可以参考下
2022-11-13

带你认识CSS3中新的长度单位

编程学习网:众所周知,在编写css过程中,我们通常要为元素的位置、尺寸精确地定义一些值。因为一个排列无序、杂乱无章的页面不可能给别人留下什么好的印象。而这时,我们就离不开长度单位的帮忙了。随着CSS的不断发展,在CSS3中引入了几个新的长度单位,今天小编就带大家一起认识它们。
带你认识CSS3中新的长度单位
2024-04-23

带你认识机房防雷的知识点

  随着通信技术、计算机网络技术的飞速发展,计算机和网络越来越深入人们生活和工作中,同时也预示着数字化、信息化时代的来临。这些微电子网络设备的普遍应用,使得防雷的问题显得越来越重要。今天小编要给大家分享一篇教程,那就是:带你认识机房防雷的知识点。  一、雷击的种类  首先小编要为大家介绍的是雷击的种类,电力线是雷电侵入
带你认识机房防雷的知识点
2024-04-18

带你初步认识网页中的DIV

编程学习网:网页设计中常用的一些标签是必须要掌握的,但是有很多的标签元素理解起来并不是特别的容易,也是让人很容易混淆,刚开始学习网页设计的朋友可能会感觉到并不是好理解,因为太专业的解释往往让人很难理解,下面一起来学习了解一下。
带你初步认识网页中的DIV
2024-04-23

重新认识MySQL中的COUNT语句

在数据库的增删改查操作中,使用最频繁的就是查询操作。而在所有查询操作中,统计数量操作更是经常被用到。关于数据库中行数统计,无论是MySQL还是Oracle亦或者是SqlServer,都有一个函数可以使用,那就是COUNT。而对于COUNT,有几个问题很值得去思
重新认识MySQL中的COUNT语句
2020-03-25

好程序员带你认识HTML5中的WebSocket

  好程序员带你认识HTML5中的WebSocket,在HTML5 规范中,我最喜欢的Web技术就是正迅速变得流行的 WebSocket API。WebSocket 提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术。这个新的
2023-06-03

带你认识思科路由器的端口

  Cisco路由器是一个具备用于连接不同网络设备的综合服务多种功能的集成多业务路由器。思科路由器端口是路由器网络设备里面一定需要涉及到的知识,思科路由器端口管理以及合理的最大化应用都将使得我们继续为这一个知识进行研究。今天小编给大家带来的教程是:带你认识思科路由器的端口。  大家都应该知道其实思科路由器端口是辅助管理
带你认识思科路由器的端口
2024-04-17

带你认识VLAN的六种划分原则

  虚拟局域网(VLAN)是一组逻辑上的设备和用户,这些设备和用户并不受物理位置的限制,可以根据功能、部门及应用等因素将它们组织起来,相互之间的通信就好像它们在同一个网段中一样,由此得名虚拟局域网。在这一篇教程里面,小编主要和大家简单的介绍一下:带你认识VLAN的六种划分原则。  第一种原则:基于MAC地址划分VLAN
带你认识VLAN的六种划分原则
2024-04-18

带你认识HTTP协议的通用头域

  超文本传输协议(HTTP,HyperTextTransferProtocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收html页面的方法。现在就跟着小编共同来学习一下:带你认识HTTP协议的通用头域。  无论你何时浏览一个网页,你的电脑
带你认识HTTP协议的通用头域
2024-04-18

带你认识,19个学习Python的小技巧!

如果你之前是一个c,c++,java的程序员,同时在学习python,或者干脆就是一个刚刚学习编程的新手,那么你应该会看到很多特别有用能让你感到惊奇的实用技巧。每一个技巧和语言用法都会在一个个实例中展示给大家,也不需要有其他的说明。但是因为
2023-06-02

带你认识分布式交换机中的NetFlow

  NetFlow利用标准的交换模式处理数据流的第一个IP包数据,生成NetFlow缓存,随后同样的数据基于缓存信息在同一个数据流中进行传输,不再匹配相关的访问控制等策略,NetFlow缓存同时包含了随后数据流的统计信息。现在小编给大家带来的教程是:带你认识分布式交换机中的NetFlow。  不知道大家是否知道数据流服
带你认识分布式交换机中的NetFlow
2024-04-18

带你全面认识Java中的异常处理

在你所写过的代码中,你已经接触过一些异常了,我们可以通过一些简单的代码让我们理解一些简单的异常,下面这篇文章主要给大家介绍了关于Java中异常处理的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
2022-12-26

带你认识WatchGuard的智能分层安全技术

  WGRD是世界领先的高效率以及全系列Internet安全方案供应商,是全球排名前五位的专门生产防火墙的公司之一。WatchGuard公司1996年成立于美国的华盛顿西雅图,并在北美、南美、EMEA以及亚洲等地设有办事处,全球员工总数约300多名。现在小编给大家带来的教程是:带你认识WatchGuard的智能分层安全
带你认识WatchGuard的智能分层安全技术
2024-04-18

一文带你认识Java中的Object类和深浅拷贝

任何变成语言中,其实都有浅拷贝和深拷贝的概念,Java中也不例外,下面这篇文章主要给大家介绍了关于Java中Object类和深浅拷贝的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-05-17

一文带你认识python源文件中的字符编码

今天就跟大家聊聊有关一文带你认识python源文件中的字符编码,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动
2023-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录