MyBatis的动态SQL之OGNL(Object-Graph Navigation Language)表达式以及各种标签的用法
MyBatis的动态SQL
- 1、if标签的用法
- 2、choose标签的用法
- 3、where标签
- 4、set标签
- 5、trim的用法
- 6、foreach标签
- 7、bind标签
使用过JDBC或者是其他的ORM框架的开发者都知道,在很多操作中都需要去根据具体的条件进行SQL语句的拼接,并且在有些时候一些标点符号、空格之类的东西会导致开发工作很难去进行。而MyBatis的动态SQL就为了解决这样的问题应用而生的。
在MyBatis3版本之前,使用动态的SQL需要使用非常多的标签,并且非常麻烦。但是随着MyBatis的不断发展,它提供了强大的OGNL(Object-Graph
Navigation Language)表达式语言,用着种语言来消除多余的标签。那么下面我们就来看看MyBatis提供的标签有哪些。
1、if标签的用法
if标签常被用在where语句中,用来判断某个参数值是否满足条件。当然后来随着越来越多的应用,它也会被用于update语句用来判断某个字段是否被更新,或者是在insert语句中用来判断某个字段是否有值要插入。
假设,现在有一个多条件查询的功能需要开发,这些条件都是需要组合查询的。遇到这样的需求的时候,就需要我们去编写一个SQL来完成条件的查询。那么这个时候问题来了,对于组合查询来讲,有些字段需要模糊查询、有些字段需要精准匹配。按照传统的写法,代码如下。
<select id="test" resultType="com.demo.bean.User">select id , name ,age, address from user where name like concat('%',#{username},'%') and age = #{age}
</select>
这个时候执行这个语句,只有当我们同时输入了name和age两个参数的时候这个SQL才会被正确的执行。如果单纯的只提供一个参数的时候这个SQL就得不到我们想要的结果。这个时候我们就可以将上面的查询进行修改。
<select id="test" resultType="com.demo.bean.User">select id , name ,age, address from user where 1=1<if test="name!=null and name!=''">and name like concat('%',#{username},'%') </if><if test="age!=null and age!=''">and age = #{age}</if>
</select>
这个时候,当我们执行这条语句的时候,如果name参数不传的话那么OGNL表达式就会判断是否为空,如果表达式为true那么就会将对应的条件语句拼接到SQL中,如果为false则不会将条件语句进行拼接。
这里需要注意的就是,在使用if标签的时候它有一个test的属性是用来编写OGNL表达式的,并且这个表达式可以支持任意字段的判断;而且判断条件只限于String类型的字段值是否存在;当有多个条件需要判断的时候,可以用and或者是or进行连接
当然上面提到的在update、insert语句中的使用方式也是类似的。
2、choose标签的用法
上面我们介绍了关于if标签的用法,但是if标签的用法中并没有提供一个if……else……类似的用法,那么如果想要实现这种逻辑操作,那么就需要用到 choose when otherwise标签了。
在一个choose标签中包含了两个子标签 when 和 otherwise ,并且一个choose中至少有一个when,可以有0个或者1个otherwise。
例如,在有些场景中有这样的操作,使用用户名、手机号、身份证号查询,这个时候就需要将这三个条件进行组合进行查询。也许这里会有人说,直接使用or语句进行连接不就可以了么?当然这样也是可以的。如果说是要优先使用用户名查询、其次是手机号、最后是身份证号。这样的需求如何来编写这个SQL呢?
<select id="test" resultType="com.demo.bean.User">select id , name ,age, address from user where 1=1<choose><when test="name!=null and name!=''">and name like concat('%',#{username},'%') </when><when test="age!=null and age!=''">and age = #{age}</when><otherwise>and 1=2</otherwise> </choose>
</select>
需要注意的是在使用这个逻辑语句的时候一定要 保证逻辑的紧密性,不然就会出现严重的SQL错误。在上面这个查询中,如果otherwise没有限制的话,那么所有满足条件的用户都会被查询出来。那么这个时候就会导致返回多条用户信息,但是在接收参数中只接受一条用户信息的情况出现。但是如果我们加上了条件之后,就会导致用户查询不到的情况发生,无论如何查询都无法查询到用户。
3、where标签
首先where标签的作用,就是如果这个标签中存在返回值,那么就会插入一个where条件语句,如果where后面的字符串是and或者是or开头的,那么就会将其剔除。这样的话,上面的标签就可以写成如下的样子。
<select id="test" resultType="com.demo.bean.User">select id , name ,age, address from user <where><if test="name!=null and name!=''">and name like concat('%',#{username},'%') </if><if test="age!=null and age!=''">and age = #{age}</if></where
</select>
这个时候当where条件中的if没有一个满足的时候where标签中就没有内容,所以按照上面的说法,where标签就不会出现在查询语句中,也就不会出现条件不匹配的问题。如果if标签中有满足条件的语句那么where条件会自动的将这些条件进行拼接然后使用。这样我们就不需要再使用where 1=1 这样的操作了。
4、set标签
set标签的作用:就是如果这标签中包含了对应的返回值,那么就会插入一个set,如果后面是逗号结尾,就会剔除这个逗号。使用如下
<update id="test">update user <set><if test="name!=null and name!=''">name = #{username}, </if><if test="age!=null and age!=''">age = #{age},</if>id = #{id}</set>where id = #{id}
</update >
在set标签的用法中,SQL后面的逗号会自动剔除,但是如果set标签中没有满足条件的内容,照样也会出现问题。为了避免这样的问题出现,对于update语句中的条件一定要出现根据某个条件进行更新操作,并且在更新的时候对应的值应该是不需要进行判断,默认就是被传入的。
5、trim的用法
与where和set标签一样,trim标签可以代替where和set来完成对应的操作,其底层实现就是通过TrimSqlNode来实现。
trim标签有如下的属性
- prefix :内容增加prefix前缀
- prefixOverrides:把内容前缀字符去掉
- suffix:增加后缀
- suffixOverrides:取消后缀
6、foreach标签
<foreach 标签主要用在构建 in 条件中,它可以在 SQL 语句中迭代一个集合。
<foreach 标签的属性主要有 item、index、collection、open、separator、close。
- item 表示集合中每一个元素进行迭代时的别名。
- index 指定一个名字,用于表示在迭代过程中每次迭代到的位置。
- open 表示该语句以什么开始。
- separator 表示在每次进行迭代之间以什么符号作为分隔符。
- close 表示以什么结束。
在使用 元素时,最关键、最容易出错的是 collection 属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下 3 种情况:
- 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
- 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
- 如果传入的参数是多个,需要把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。
接下来针对上述三种情况进行演示:
(1)单参数且参数类型是List
在IStudentDao添加方法。
List<Student> forEachTest1(List<Integer> list);
在studentMapper.xml中添加sql映射语句。
<select id="forEachTest1" resultType="com.day1.entity.Student">select * from t_student where age in<foreach collection="list" index="index" item="item" open="(" separator="," close=")">#{item}</foreach></select>
进行测试。
@Testpublic void testForEach01() throws IOException {//1、读取配置文件InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");//2、创建SqlSessionFactory工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(in);//3、使用工厂生产SqlSession对象SqlSession sqlSession = factory.openSession();//4、使用SqlSession创建dao接口的代理对象IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);//5、使用代理对象执行方案List<Integer> list = new ArrayList<>();list.add(21);list.add(43);list.add(19);List<Student> students = studentDao.forEachTest1(list);for(Student stu : students){System.out.println(stu);}//6、释放资源sqlSession.close();in.close();}
(2)单参数且参数类型是array
在IStudentDao添加方法。
List<Student> forEachTest2(int[] ages);
在studentMapper.xml中添加sql映射语句。
<select id="forEachTest2" resultType="com.day1.entity.Student">select * from t_student where age in<foreach collection="array" index="index" item="item" open="(" separator="," close=")">#{item}</foreach></select>
进行测试。
@Testpublic void testForEach02() throws IOException {//1、读取配置文件InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");//2、创建SqlSessionFactory工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(in);//3、使用工厂生产SqlSession对象SqlSession sqlSession = factory.openSession();//4、使用SqlSession创建dao接口的代理对象IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);//5、使用代理对象执行方案int[] ages = new int[]{19, 56};List<Student> students = studentDao.forEachTest2(ages);for(Student stu : students){System.out.println(stu);}//6、释放资源sqlSession.close();in.close();}
(3)封装map
在IStudentDao添加方法。
List<Student> forEachTest3(Map<String, Object> map);
在studentMapper.xml中添加sql映射语句。
<select id="forEachTest3" resultType="com.day1.entity.Student">select * from t_student where age > #{age} or address in<foreach collection="locations" index="index" item="item" open="(" separator="," close=")">#{item}</foreach></select>
进行测试。
@Testpublic void testForEach03() throws IOException {//1、读取配置文件InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");//2、创建SqlSessionFactory工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(in);//3、使用工厂生产SqlSession对象SqlSession sqlSession = factory.openSession();//4、使用SqlSession创建dao接口的代理对象IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);//5、使用代理对象执行方案List<String> locations = new ArrayList<>();locations.add("北京");locations.add("河北");locations.add("安徽");Map<String, Object> map = new HashMap<>();map.put("age", 30);map.put("locations", locations);List<Student> students = studentDao.forEachTest3(map);for(Student stu : students){System.out.println(stu);}//6、释放资源sqlSession.close();in.close();}
7、bind标签
通常在进行模糊查询时,如果使用“${}”拼接字符串,则无法防止 SQL 注入问题。如果使用字符串拼接函数或连接符号,但不同数据库的拼接函数或连接符号不同,MySQL 用的是的 concat 函数、Oracle 则是连接符号“||”,这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。MyBatis 提供了 元素来解决这一问题。
<bind标签可以使用OGNL表达式创建一个变量并将其绑定到上下文中。标签的两个属性都是必选项:name 为绑定到上下文的变量名;value 为 OGNL 表达式。
(1)在IStudentDao添加方法。
List<Student> testBind(Student student);
(2)在studentMapper.xml中添加sql映射语句。
<!--使用bind元素进行模糊查询--><select id="testBind" resultType="com.day1.entity.Student" parameterType= "com.day1.entity.Student"><!-- bind 中的 username 是 com.day1.entity.Student 的属性名--><bind name="username" value="'%' + username + '%'"/>select * from t_student where username like #{username}</select>
(3)进行测试。
@Testpublic void testBind() throws IOException {//1、读取配置文件InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");//2、创建SqlSessionFactory工厂SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(in);//3、使用工厂生产SqlSession对象SqlSession sqlSession = factory.openSession();//4、使用SqlSession创建dao接口的代理对象IStudentDao studentDao = sqlSession.getMapper(IStudentDao.class);//5、使用代理对象执行方案Student student = new Student();student.setUsername("王");List<Student> students = studentDao.testBind(student);for(Student stu : students){System.out.println(stu);}//6、释放资源sqlSession.close();in.close();}
相关文章:
MyBatis的动态SQL之OGNL(Object-Graph Navigation Language)表达式以及各种标签的用法
MyBatis的动态SQL 1、if标签的用法2、choose标签的用法3、where标签4、set标签5、trim的用法6、foreach标签7、bind标签 使用过JDBC或者是其他的ORM框架的开发者都知道,在很多操作中都需要去根据具体的条件进行SQL语句的拼接,并且在有些时候一些标点符号…...
基于Java+Springboot+Vue的二次元商城网站设计与实现
博主介绍:✌擅长Java、微信小程序、Python、Android等,专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案…...
MyBatis操作数据库实现
说明:MyBatis是作用于三层架构开发,数据访问层(Data Access Object)的框架,用于访问数据库,对数据进行操作。 一、环境搭建 首先,创建一个SpringBoot模块,然后把MyBatis的环境搭建…...
Git GitLab 使用及规范
Git 基本操作 Git安装配置及基本使用 从官网下载安装包,手动完成安装。打开Git Bash命令行工具,执行命令ssh-keygen -t rsa -C Email-Addresss生成一个密钥对。登录到GitLab,点击右上角你的用户头像,点击Edit Profile settings&…...
【SpringCloud——Sentinel】
一、什么是雪崩? 微服务调用链路中的某个服务发生故障,引起整个链路中的所有微服务都不可用,这就是雪崩。 二、解决雪崩问题的常见措施 1、超时处理 设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休…...
面试专题:计算机网络常见面试点总结
socket、tcp、udp、http 的认识及区别 socket、tcp、udp、http 的认识及区别 一、先来一个讲TCP、UDP和HTTP关系的 1、TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传…...
PageHelper失效问题
问题出现记录: 修改代码后,出现分页失效问题,原本的代码再设置了 PageHelper.startPage(pageNum, pageSize);后只有一个mysql查询,我在原本的业务查询前,新增了其他的Mysql查询,导致原需要分页的查询失效 …...
Linux常用命令——grep命令
在线Linux命令查询工具 grep 强大的文本搜索工具 补充说明 grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本&…...
学校热水供应系统方案
学校热水供应系统是现代化校园建设的重要组成部分。一套高效、可靠、安全、环保的热水供应系统,不仅能够满足学生、教职工的日常生活需求,也能提高学校形象和竞争力。 在设计学校热水供应系统方案时,需要考虑以下几个方面: 一、热…...
chatgpt赋能python:Python怎么写绝对值
Python怎么写绝对值 在Python编程语言中,有很多常用函数。其中包括求绝对值的函数。在这篇文章中,我们将介绍如何在Python中使用绝对值函数,并提供一些示例。 什么是绝对值函数? 绝对值函数是一个数学中常用的函数,…...
研发工程师玩转Kubernetes——Node亲和性requiredDuringSchedulingIgnoredDuringExecution几种边界实验
在《研发工程师玩转Kubernetes——使用Node特性定向调度Pod》中,我们提到requiredDuringSchedulingIgnoredDuringExecution只有在规则被满足的时候才能执行调度。本节我们将测试几种边界情况,看看Kubernetes的行为。 没有满足的条件 假设我们测试的Nod…...
OpenCV中的图像处理3.9(六)轮廓线特征与属性
目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线:入门目标什么是轮廓线?如何绘制轮廓线?轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮…...
burpsuite+xray实现联动测试(手动分析和自动化测试同时进行)
目的:安全测试过程中手动分析测试与xray自动化扫描测试结合,这样可以从多层保障安全测试的分析,针对平台业务接口量大的安全测试是十分有用的,可以实现双向测试同时开始。 xray简介 xray 是一款功能强大的安全评估工具ÿ…...
2023年专业连锁行业研究报告
第一章 行业概况 专业连锁行业是指以连锁经营模式运营的公司,其主要业务涵盖零售、餐饮、酒店、医疗、教育等领域。这些公司通过规模化、标准化的经营模式和供应链管理,提供专业化、高质量的产品和服务。专业连锁行业在全球范围内蓬勃发展,并…...
Mysql数据库(六):基本的SELECT语句
基本的SELECT语句 前言一、SELECT...二、SELECT ... FROM三、列的别名四、去除重复行五、空值参与运算六、着重号七、查询常数八、显示表结构九、过滤数据 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注博主&#…...
在CentOS7环境中,实现使用openresty配置文件,达到jwt指定用户userid不能访问的效果
#在CentOS7环境中,实现使用openresty配置文件,达到jwt指定用户userid不能访问的效果。 首先,你需要安装 OpenResty 和 JWT 组件: 安装 OpenResty 参考 OpenResty 的官方安装文档,在终端执行如下命令: $…...
SpringBoot 源码分析初始化应用上下文(1)-createApplicationContext
前言:springBoot的版本是 2.2.4.RELEASE 一、入口 /*** Run the Spring application, creating and refreshing a new* {link ApplicationContext}.* param args the application arguments (usually passed from a Java main method)* return a running {link A…...
STM32队列
目录 什么是队列? 队列特点 1. 数据入队出队方式 2. 数据传递方式 3. 多任务访问 4. 出队、入队阻塞 队列相关 API 函数 1. 创建队列 参数: 2. 写队列 参数: 返回值: 3. 读队列 参数: 返回值…...
探索Beyond Compare:让文件比较和管理变得简单高效
在这个信息爆炸时代,我们的日常生活和工作中需要处理大量的数据和文档。在这个过程中,有时候我们会面临找出不同文件之间的差异、合并重复内容等需求。那么,有没有一款软件可以帮助我们轻松地完成这些任务呢?答案当然是肯定的&…...
动态网站Servelt基础
文章目录 一、Servlet基础(一)Servlet概述1、Servlet是什么2、Servlet容器3、Servlet应用程序的体系结构 (二)Servlet的特点1、功能强大2、可移植3、性能高效4、安全性高5、可扩展 (三)Servlet接口1、Servl…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
前端工具库lodash与lodash-es区别详解
lodash 和 lodash-es 是同一工具库的两个不同版本,核心功能完全一致,主要区别在于模块化格式和优化方式,适合不同的开发环境。以下是详细对比: 1. 模块化格式 lodash 使用 CommonJS 模块格式(require/module.exports&a…...
