当前位置: 首页 > news >正文

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框架的开发者都知道&#xff0c;在很多操作中都需要去根据具体的条件进行SQL语句的拼接&#xff0c;并且在有些时候一些标点符号…...

基于Java+Springboot+Vue的二次元商城网站设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…...

MyBatis操作数据库实现

说明&#xff1a;MyBatis是作用于三层架构开发&#xff0c;数据访问层&#xff08;Data Access Object&#xff09;的框架&#xff0c;用于访问数据库&#xff0c;对数据进行操作。 一、环境搭建 首先&#xff0c;创建一个SpringBoot模块&#xff0c;然后把MyBatis的环境搭建…...

Git GitLab 使用及规范

Git 基本操作 Git安装配置及基本使用 从官网下载安装包&#xff0c;手动完成安装。打开Git Bash命令行工具&#xff0c;执行命令ssh-keygen -t rsa -C Email-Addresss生成一个密钥对。登录到GitLab&#xff0c;点击右上角你的用户头像&#xff0c;点击Edit Profile settings&…...

【SpringCloud——Sentinel】

一、什么是雪崩&#xff1f; 微服务调用链路中的某个服务发生故障&#xff0c;引起整个链路中的所有微服务都不可用&#xff0c;这就是雪崩。 二、解决雪崩问题的常见措施 1、超时处理 设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休…...

面试专题:计算机网络常见面试点总结

socket、tcp、udp、http 的认识及区别 socket、tcp、udp、http 的认识及区别​ 一、先来一个讲TCP、UDP和HTTP关系的 1、TCP/IP是个协议组&#xff0c;可分为三个层次&#xff1a;网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传…...

PageHelper失效问题

问题出现记录&#xff1a; 修改代码后&#xff0c;出现分页失效问题&#xff0c;原本的代码再设置了 PageHelper.startPage(pageNum, pageSize);后只有一个mysql查询&#xff0c;我在原本的业务查询前&#xff0c;新增了其他的Mysql查询&#xff0c;导致原需要分页的查询失效 …...

Linux常用命令——grep命令

在线Linux命令查询工具 grep 强大的文本搜索工具 补充说明 grep&#xff08;global search regular expression(RE) and print out the line&#xff0c;全面搜索正则表达式并把行打印出来&#xff09;是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&…...

学校热水供应系统方案

学校热水供应系统是现代化校园建设的重要组成部分。一套高效、可靠、安全、环保的热水供应系统&#xff0c;不仅能够满足学生、教职工的日常生活需求&#xff0c;也能提高学校形象和竞争力。 在设计学校热水供应系统方案时&#xff0c;需要考虑以下几个方面&#xff1a; 一、热…...

chatgpt赋能python:Python怎么写绝对值

Python怎么写绝对值 在Python编程语言中&#xff0c;有很多常用函数。其中包括求绝对值的函数。在这篇文章中&#xff0c;我们将介绍如何在Python中使用绝对值函数&#xff0c;并提供一些示例。 什么是绝对值函数&#xff1f; 绝对值函数是一个数学中常用的函数&#xff0c;…...

研发工程师玩转Kubernetes——Node亲和性requiredDuringSchedulingIgnoredDuringExecution几种边界实验

在《研发工程师玩转Kubernetes——使用Node特性定向调度Pod》中&#xff0c;我们提到requiredDuringSchedulingIgnoredDuringExecution只有在规则被满足的时候才能执行调度。本节我们将测试几种边界情况&#xff0c;看看Kubernetes的行为。 没有满足的条件 假设我们测试的Nod…...

OpenCV中的图像处理3.9(六)轮廓线特征与属性

目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线&#xff1a;入门目标什么是轮廓线&#xff1f;如何绘制轮廓线&#xff1f;轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮…...

burpsuite+xray实现联动测试(手动分析和自动化测试同时进行)

目的&#xff1a;安全测试过程中手动分析测试与xray自动化扫描测试结合&#xff0c;这样可以从多层保障安全测试的分析&#xff0c;针对平台业务接口量大的安全测试是十分有用的&#xff0c;可以实现双向测试同时开始。 xray简介 xray 是一款功能强大的安全评估工具&#xff…...

2023年专业连锁行业研究报告

第一章 行业概况 专业连锁行业是指以连锁经营模式运营的公司&#xff0c;其主要业务涵盖零售、餐饮、酒店、医疗、教育等领域。这些公司通过规模化、标准化的经营模式和供应链管理&#xff0c;提供专业化、高质量的产品和服务。专业连锁行业在全球范围内蓬勃发展&#xff0c;并…...

Mysql数据库(六):基本的SELECT语句

基本的SELECT语句 前言一、SELECT...二、SELECT ... FROM三、列的别名四、去除重复行五、空值参与运算六、着重号七、查询常数八、显示表结构九、过滤数据 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注博主&#…...

在CentOS7环境中,实现使用openresty配置文件,达到jwt指定用户userid不能访问的效果

#在CentOS7环境中&#xff0c;实现使用openresty配置文件&#xff0c;达到jwt指定用户userid不能访问的效果。 首先&#xff0c;你需要安装 OpenResty 和 JWT 组件&#xff1a; 安装 OpenResty 参考 OpenResty 的官方安装文档&#xff0c;在终端执行如下命令&#xff1a; $…...

SpringBoot 源码分析初始化应用上下文(1)-createApplicationContext

前言&#xff1a;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队列

目录 什么是队列&#xff1f; 队列特点 1. 数据入队出队方式 2. 数据传递方式 3. 多任务访问 4. 出队、入队阻塞 队列相关 API 函数 1. 创建队列 参数&#xff1a; 2. 写队列 参数&#xff1a; 返回值&#xff1a; 3. 读队列 参数&#xff1a; 返回值&#xf…...

探索Beyond Compare:让文件比较和管理变得简单高效

在这个信息爆炸时代&#xff0c;我们的日常生活和工作中需要处理大量的数据和文档。在这个过程中&#xff0c;有时候我们会面临找出不同文件之间的差异、合并重复内容等需求。那么&#xff0c;有没有一款软件可以帮助我们轻松地完成这些任务呢&#xff1f;答案当然是肯定的&…...

动态网站Servelt基础

文章目录 一、Servlet基础&#xff08;一&#xff09;Servlet概述1、Servlet是什么2、Servlet容器3、Servlet应用程序的体系结构 &#xff08;二&#xff09;Servlet的特点1、功能强大2、可移植3、性能高效4、安全性高5、可扩展 &#xff08;三&#xff09;Servlet接口1、Servl…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...

Linux安全加固:从攻防视角构建系统免疫

Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...