详解Mybatis之动态sql问题

编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
Maven版本:apache-maven-3.6.3
Mybatis版本:3.5.6

文章目录

  • 一. 在sql映射文件中如何写注释?
  • 二. 什么是动态sql?
  • 三. 动态sql常用标签有哪些?
    • 3.1 if标签
    • 3.2 where标签
    • 3.3 trim标签
    • 3.4 set标签
    • 3.5 choose标签
    • 3.6 foreach标签
    • 3.7 sql标签


在这里插入图片描述


一. 在sql映射文件中如何写注释?

关于XXXMapper接口对应的映射文件里SQL中的注释

👉语法

①方式一

//mysql的注释	
-- 1=1

②方式二

//xml的注释
<!-- 1=1  -->

使用这两种注释方式各有什么不同呢?

👉请看如下测试

代码示例如下:

①使用第一种注释

<!--  根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询  --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE-- 1=1<if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>

在这里插入图片描述

②使用第二种注释

<!--  根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询  --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE
<!--             1=1--><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>

在这里插入图片描述

💡结论

通过以上二者运行测试结果对比,所以在需要使用注释时,推荐使用第二种注释方式


二. 什么是动态sql?

👉定义

  1. 动态sql指的是sql语句可动态化
  2. Mybatis的动态sql中支持OGNL表达式语言,OGNL(Object Graph Navigation
    Language)是对象图导航语言

❗注意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1XJyWZlo-1690458988415)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1682994155884.png)]

👉用法案例

不指定查询条件,查询对应员工信息,即当你传入id,程序就根据id去查,传入什么条件,就去根据此条件去查(多个条件不确定)

代码示例如下

①在EmployeeMapper接口下书写相应的方法

//动态的sql方式,即不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByopr(Employee employee);

②在EmployeeMapper接口相应的sql

<!--  根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询  --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE<if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>

③测试

@Test
public void test01(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数(无参会报错,没有第一个参数也会报错)Employee employee=new Employee();List<Employee> employees = employeeMapper.selectEmpByopr(employee);//遍历集合employeesfor (Employee employee1 : employees) {System.out.println(employee1);}} catch (IOException e) {e.printStackTrace();}}

❓但是这样会出现一个问题,即不传参会报错,没有第一个参数也会报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H8BuZQxZ-1690458988415)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1682997746252.png)]

💡原因分析

不传参时,mybatis解析sql的过程中走到where的部分,无参,会进入where里,但不会执行里面的任意if判断,where后没有任何赋值表达式,此sql为非法sql,故报错。没有第一个参数时也会报类似的问题。

👉解决方案

①在第二步中的where里加上 1=1,作为条件恒等式(老版本的解决措施)

在这里插入图片描述

②使用where标签

代码示例如下:

<!--  根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询  --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></where></select>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GPGt0JYh-1690458988416)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1682999094227.png)]


三. 动态sql常用标签有哪些?

3.1 if标签

👉功能

用于完成简单的判断

示例代码如下:

 //如果属性id不为空,就将传入的参数id赋值给sql中的字段id<if test="id !=null">id=#{id}</if>

3.2 where标签

👉功能:

用于解决where关键字及where后第一个and或or的问题

示例代码如下:

<where><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if>
</where>

3.3 trim标签

👉功能

可以在条件判断完的SQL语句前后添加或者去掉指定的字符

👉属性

  • prefix添加前缀
  • prefixOverrides去掉前缀
  • suffix添加后缀
  • suffixOverrides去掉后缀

👉用法案例

不指定查询条件,查询对应员工信息(trim标签优化版)

代码示例如下:

①在EmployeeMapper接口定义相应的方法

//不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByEmpTrim(Employee employee);

②在EmployeeMapper接口对应的映射文件中定义相应的sql

<!--  根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版)  -->
<select id="selectEmpByEmpTrim" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<!--  给下面的sql语句加上前缀 where,去掉后缀and      --><trim prefix="where" suffixOverrides="and"><if test="id !=null">id=#{id} and</if><if test="lastName != null">last_name=#{lastName}  and</if><if test="email != null">email=#{email}  and</if><if test="salary != null">salary=#{salary}   and</if></trim>
</select>

③测试

@Testpublic void test02(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数Employee employee=new Employee();/*  employee.setLastName("jack");employee.setSalary(5600.0);
*/List<Employee> employees = employeeMapper.selectEmpByEmpTrim(employee);//遍历集合employeesfor (Employee employee1 : employees) {System.out.println(employee1);}} catch (IOException e) {e.printStackTrace();}}

在这里插入图片描述

在这里插入图片描述

trim标签运行流程详解

在这里插入图片描述

3.4 set标签

👉功能

主要用于解决set关键字及多出一个【,】问题

👉用法案例

修改员工的信息

代码示例如下:

①在EmployeeMapper接口中定义修改员工的信息的方法

//修改员工的信息
public void updateEmp(Employee employee);

②在EmployeeMapper接口对应的映射文件中书写相应的sql

问题版(会出现多一个【,】问题

<update id="updateEmp">updatetbl_employeeset<if test="lastName != null">last_name=#{lastName}  ,</if><if test="email != null">email=#{email}  ,</if><if test="salary != null">salary=#{salary} ,</if>whereid=#{id}
</update> 

set标签解决问题版

<update id="updateEmp">updatetbl_employee<set><if test="lastName != null">last_name=#{lastName}  ,</if><if test="email != null">email=#{email}  ,</if><if test="salary != null">salary=#{salary} ,</if></set>whereid=#{id}
</update>

③测试

@Test
public void test03(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数Employee employee=new Employee();employee.setId(1);employee.setLastName("tom");employee.setSalary(16800.0);employeeMapper.updateEmp(employee);xml} catch (IOException e) {e.printStackTrace();}
}

使用问题版的sql进行测试

在这里插入图片描述

使用set标签解决问题版的sql进行测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tYwOzFHZ-1690458988420)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1683014982189.png)]

3.5 choose标签

👉功能

类似java中if-else【switch-case】结构

👉应用场景

应用于单个条件不确定的业务场景

👉用法案例

不指定查询条件,查询对应的员工信息(单个条件不确定的)

代码示例如下:

①在EmployeeMapper接口书写相应的方法

//不指定查询条件,查询对应员工信息(单个条件不确定的)
public List<Employee> selectEmpByOneOpr(int empId);

②在EmployeeMapper接口对应的映射文件中书写相应的sql

<!--  根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版)  -->
<select id="selectEmpByOneOpr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where><choose><when test="id !=null">id=#{id}</when><when test="lastName != null">last_name=#{lastName}</when><when test="email != null">email=#{email}</when><otherwise>salary=#{salary}</otherwise></choose></where></select>

③测试

@Test
public void test04(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);System.out.println(employees);} catch (IOException e) {e.printStackTrace();}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e7bR0Hli-1690458988421)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1683016763843.png)]

3.6 foreach标签

👉功能

类似java中for循环

👉标签属性

  • collection要迭代的集合
  • item当前从集合中迭代出的元素
  • separator元素与元素之间的分隔符
  • open开始字符
  • close结束字符

👉应用场景

🚩 ①遍历迭代

用法案例

通过多个id获取员工的信息 【EmpIds:员工id的集合】

代码示例如下:

a.在EmployeeMapper接口定义相应的方法

/*** 通过多个id获取员工的信息 【EmpIds:员工id的集合】* @param EmpIds* @return*/
public List<Employee> selectEmpByIds(@Param("ids") List<Integer> EmpIds);

b.在EmployeeMapper接口对应的映射文件中定义相应的sql

 <select id="selectEmpByIds" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where>`id` in(<foreach collection="ids" item="id" separator=",">#{id}</foreach>)</where></select>

c.测试

@Test
public void test04(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);System.out.println(employees);} catch (IOException e) {e.printStackTrace();}
}

在这里插入图片描述

🚩②批量导入

用法案例

批量添加员工数据

代码示例如下:

a.在EmployeeMapper接口定义相应的方法

  //批量添加员工数据public void batchInsertEmp(@Param("emps") List<Employee> employees);

b.在EmployeeMapper接口对应的映射文件中定义相应的sql

// 批量添加员工数据,使用insert标签书写相应的sql
<insert id="batchInsertEmp">insert intotbl_employee(last_name,email,salary)values<foreach collection="emps" item="emp" separator=",">(#{emp.lastName},#{emp.email},#{emp.salary})</foreach></insert>

c.测试

@Test
public void test06(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//定义要添加的员工集合List<Employee> list=new ArrayList<>();list.add(new Employee("zhangsan","sdhjsd@qq.com",6700.0));list.add(new Employee("wangwu","dddhjsd@123.com",9700.0));employeeMapper.batchInsertEmp(list);sqlSession.commit();} catch (IOException e) {e.printStackTrace();}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TE2Af2O2-1690458988422)(C:\Users\king\AppData\Roaming\Typora\typora-user-images\1683030856816.png)]

在这里插入图片描述

3.7 sql标签

👉功能

提取可重用SQL片段

❗注意

该SQL片段可以是一个完整的sql语句,也可以是一个sql语句中的某个片段)

👉用法案例

使用sql标签对3.6小节中的应用场景1的案例里映射文件里的的”select xxx,xxxx,xxx from
xxxx”部分提取出来,作为一个可重用的sql片段,在select>标签内引入该sql片段

代码示例如下:

①使用sql标签抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段

<!-- 抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段   -->
<sql id="select_employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`</sql><select id="selectEmpByIds" resultType="employee"><!--  将刚才抽取的sql片段select_employee引入进来  --><include refid="select_employee"></include><where>`id` in(<foreach collection="ids" item="id" separator=",">#{id}</foreach>)</where></select>

②测试运行

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/10907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pycharm 使用远程服务器 jupyter (本地jupyter同理)

1. 远程服务器miniconda 环境中创建jupyter环境 # 1. 激活环境 conda activate envname#2. 在环境中安装jupyter pip install jupyter # 或者 conda install jupyter#3. 生成jupyter_notebook_config.py文件 jupyter notebook --generate-config#4. 设置密码 jupyter noteboo…

Spark编程-SparkSQL

SparkSql能做些啥 Spark SQL的核心概念是DataFrame&#xff0c;它是一个分布式的数据集合&#xff0c;类似于关系数据库中的表。支持使用SQL语言直接对DataFrame进行查询,提供了丰富的内置函数和表达式&#xff0c;可以用于数据的转换、过滤和聚合等操作,支持多种数据源&#…

功能测试也可以发现数据库相关的性能问题

很多同学认为功能测试和性能测试是严格分开的&#xff0c;功能测试人员无法发现性能问题。其实不是这样的&#xff0c;功能测试人员在验证功能时也可以发现性能问题&#xff1b;一些功能反而在功能测试环境不好验证&#xff0c;需要在性能环境上测试。 今天咱们就说一下测试涉及…

Leetcode 滑动窗口题目总结

(Leetcode 滑动窗口题目总结) 1&#xff1a; 3.无重复字符的最长子串 https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/子串 和 子序列的区别&#xff1a;字串是连续的&#xff0c;子序列是非连续的。快慢指针 i 和 j&#xff0c;…

前端面试题 —— React (二)

目录 一、React 组件中怎么做事件代理&#xff1f;它的原理是什么&#xff1f; 二、React.Component 和 React.PureComponent 的区别 三、Component, Element, Instance 之间有什么区别和联系&#xff1f; 四、React声明组件有哪几种方法&#xff0c;有什么不同&#xff1f…

QT项目代码去UI界面常用开发步骤

QT项目代码去UI界面常用开发步骤 因项目开发需求&#xff0c;领导要求整个QT项目中不要用UI方式来实现界面&#xff0c;这样能保障程序运行稳定性以及代码的逻辑和可读性,先记录具体操作步骤如下&#xff1a; 1、首先我们通过拖控件的方式来实现界面的设计效果&#xff0c…

【Docker】安全及日志管理

目录 一、Docker 安全及日志管理1.1 Docker 容器与虚拟机的区别1. 隔离与共享2. 性能与损耗 1.2Docker 存在的安全问题1.Docker 自身漏洞2.Docker 源码问题 1.3 Docker 架构缺陷与安全机制1. 容器之间的局域网攻击2. DDoS 攻击耗尽资源3. 有漏洞的系统调用4. 共享root用户权限 …

DEVICENET转ETHERNET/IP网关devicenet协议

捷米JM-EIP-DNT&#xff0c;你听说过吗&#xff1f;这是一款自主研发的ETHERNET/IP从站功能的通讯网关&#xff0c;它能够连接DEVICENET总线和ETHERNET/IP网络&#xff0c;从而解决生产管理系统中协议不同造成的数据交换互通问题。 这款产品在工业自动化领域可谓是一大利器&…

特定Adreno GPU的Android设备发生冻屏问题

1&#xff09;特定Adreno GPU的Android设备发生冻屏问题 ​2&#xff09;Unity版本升级后&#xff0c;iOS加载UnityFramework bundle闪退 3&#xff09;关于RectTransfrom.rect在屏幕空间中表示的相关问题 4&#xff09;Unity Mesh泄露问题 这是第345篇UWA技术知识分享的推送&a…

Java 8 Stream流:代码简洁之道

文章目录 前言一、filter二、map三、mapToInt、mapToLong、mapToDouble四、flatMap五、flatMapToInt、flatMapToLong、flatMapToDouble六、distinct七、sorted八、peek九、limit十、forEach十一、forEachOrdered十二、toArray十三、reduce十四、collect十五、min、max十六、cou…

Llama 2 来袭 - 在 Hugging Face 上玩转它

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 引言 今天&#xff0c;Meta 发布了 Llama 2&#xff0c;其包含了一系列最先进的开放大语言模型&#xff0c;我们很高兴能够将其全面集成入 Hugging Face&#xff0c;并全力支持其发布。Llama 2 的社…

将AWS S3大文件文件上传相关的API集成为js文件,功能包括 多文件并行上传、文件分片上传、断点续传、文件分片合成、上传暂停、取消上传、文件上传进度条显示

地址 https://github.com/gk-1213/easy-s3/tree/main easy-s3 将AWS S3大文件文件上传相关的API集成为js文件&#xff0c;功能包括多文件并行上传、文件分片上传、断点续传、文件分片合成、上传暂停、取消上传、文件上传进度条显示。 暂时不包括文件分片下载相关功能&#…

linux下用docker安装mysql

1.mysql Docker镜像 docker pull mysql:[版本号 或 latest]例&#xff1a;docker pull mysql:5.7 2.查看拉取的docker镜像 docker images3.设置 Docker 卷 docker volume create mysql-data列出 Docker 已知的所有卷 docker volume ls4.运行一个 MySQL Docker 容器 docke…

2018年全国硕士研究生入学统一考试管理类专业学位联考写作试题——解析版

2018年1月真题 四、写作&#xff1a;第56~57小题&#xff0c;共65分。其中论证有效性分析30 分&#xff0c;论说文35分。 56.论证有效性分析&#xff1a; 分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600字左右的文章&#xff0c;对该论证的有…

乐维监控 | 如何快速关闭网络设备所有端口

在运维监控实践中&#xff0c;由于不同的运维人员可能会关注不同的监控指标&#xff0c;因此乐维监控在监控网络设备时&#xff0c;会默认开启所有的端口&#xff0c;尽可能多的覆盖监控指标&#xff0c;避免遗漏重要指标。但是&#xff0c;这样又会带来新的问题&#xff0c;在…

golang,gin框架的请求参数(一)--推荐

golang&#xff0c;gin框架的请求参数&#xff08;一&#xff09; gin框架的重要性不过多的强调&#xff0c;重点就gin使用中的参数传递&#xff0c;获取进行梳理文件&#xff0c;满足使用需求。 获取前端请求参数的几种方法&#xff1a; 一、获取参数【浏览器地址获取参数】…

【论文阅读】定制化diffusion微调: DreamBooth原理

论文&#xff1a;DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation 项目&#xff1a;DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation 代码&#xff1a;Dreambooth-Stable-Diffusion 1. 任务简…

Kotlin基础(八):泛型

前言 本文主要讲解kotlin泛型&#xff0c;主要包括泛型基础&#xff0c;类型变异&#xff0c;类型投射&#xff0c;星号投射&#xff0c;泛型函数&#xff0c;泛型约束&#xff0c;泛型在Android中的使用。 Kotlin文章列表 Kotlin文章列表: 点击此处跳转查看 目录 1.1 泛型基…

Unity XML1——XML基本语法

一、XML 概述 ​ 全称&#xff1a;可拓展标记语言&#xff08;EXtensible Markup Language&#xff09; ​ XML 是国际通用的&#xff0c;它是被设计来用于传输和存储数据的一种文本特殊格式&#xff0c;文件后缀一般为 .xml ​ 我们在游戏中可以把游戏数据按照 XML 的格式标…

JAVA线上问题排查降龙十八掌

现场问题一般有以下几种问题 CPU,磁盘&#xff0c;内存&#xff0c;GC问题&#xff0c;网络 同时例如jstack、jmap等工具也是不囿于一个方面的问题的&#xff0c;基本上出问题就是df、free、top 三连&#xff0c;然后依次jstack、jmap伺候&#xff0c;具体问题具体分析即可。 …