【MyBatis】动态SQL

在这里插入图片描述

文章目录

  • 前言
  • 增加操作
  • \<trim>标签
  • 查询操作
  • \<where>标签
  • 修改操作
  • \<set>标签
  • 删除操作
  • \<foreach>标签
  • \<include>标签

前言

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。具体的定义大家可以参考官方文档MyBatis动态SQL。这篇文章我们将结合动态SQL完成更加复杂的 SQL 操作。

增加操作

想必大家肯定遇到过注册某个账号的时候需要输入自己的相关信息,其中这些信息包括:必填信息和非必填信息,对于这些必填信息,我们只需要在创建表的时候将这个字段设置为非 null 就可以了,而对于那些非必选的选项,我们又该如何定义呢?

这时就需要我们使用动态标签来判断了,对于这些可以传递值和可以不传递值的字段,我们可以使用 <if> 标签来修饰:

@Insert("insert into userinfo(username,`password`,age," +"<if test='gender!=null'>gender,</if>" +"phone)" +"values(#{username},#{password},#{age}," +"<if test='gender!=null'>gender,</if>" +"#{phone})")
public Integer insertByCondition(UserInfo userInfo);

<if test="">123</if> 这个标签中 test 表示的是判断,当 test 参数中的判断为真时,那么这个标签的结果就为 <if> </if>标签之间的代码块,在这里就是123;如果 test 中的代码块的判断为假的时候,那么这个<if> 标签的结果就是空。

@Test
void insertByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("彭于晏");userInfo.setPassword("123456");userInfo.setAge(18);userInfo.setPhone("132131231");int ret = userInfoMapper.insertByCondition(userInfo);log.info(ret + "被更新");
}

然后我们调用这个方法的时候,可以不为 gender 字段传递值,如果不传递值,那么这个字段的值就为创建表时定义的默认值,也可以传递值。然后我们运行一下看能达到效果吗?

在这里插入图片描述
这里为什么会报错呢?因为 <if> 标签是属于 JavaScript 的,所以我们需要使用到 <script> 标签。

@Insert("<script>" +"insert into userinfo(username,`password`,age," +"<if test='gender!=null'>gender,</if>" +"phone)" +"values(#{username},#{password},#{age}," +"<if test='gender!=null'>gender,</if>" +"#{phone})" +"</script>")
public Integer insertByCondition(UserInfo userInfo);

在这里插入图片描述
有人会问了,使用 <if> 标签和不使用作用不是一样的吗?对于当前插入数据操作作用是一样的,但是如果我们进行的是修改操作的话,因为我们不知道用户需要修改什么信息,所以我们在写修改操作的话,就需要将所有的字段的修改操作都写上,但是如果我们不使用 <if> 标签的话,并且用户在修改的时候,某个信息没有修改话,后端SQL预处理之后是这样的:update userinfo set username=?, password=?, gender=?, phone=? where username=?,前端传递来的参数是这样的:null, null, null, 123456, 小美,也就是用户只是修改了电话号码这个字段,但是因为没有使用 <if> 标签,所以其他的字段就会被修改为 null,这就会出现问题了。而使用 <if> 标签就会这样处理:update userinfo phone=? where username=?,参数传递:123456, 小美

上面是使用注解的方式来实现 MyBatis 的,实现 MyBatis 不仅可以通过注解来实现,也可以通过 XML 的格式实现。我们看看 XML 如何实现动态 SQL。

首先我们需要告诉 MyBatis 我们的 xml 文件在哪里:

mybatis:mapper-locations: classpath:mapper/**Mapper.xml

然后在 XML 文件中写入下面代码,SQL 语句写在 <mapper> 标签中。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis20240101.mapper.UserInfoMapper"></mapper>

这里 namespace 的值是我们是使用了 MyBatis 框架操作数据库的类的全限定类名称。

<insert id="insertByCondition">insert into userinfo(username,`password`,age,<if test="gender!=null">gender,</if>phone)values(#{username},#{password},#{age},<if test="gender!=null">#{gender},</if>#{phone})
</insert>

因为 XML 文件本身就支持 JavaScript,所以我们这里不需要添加 <script> 标签,不仅如此,使用 XML 文件的方式写 MyBatis 还会有提示,所以书写动态 SQL 建议使用 XML 文件格式。

在这里插入图片描述
但是使用 <if> 标签也会存在问题,假设我们将 phone 字段也设置为动态的,并且在传递值的时候不传递 phone 的话就会出现问题。

<insert id="insertByCondition">insert into userinfo(username,`password`,age,<if test="gender!=null">gender,</if><if test="phone!=null">phone</if>)values(#{username},#{password},#{age},<if test="gender!=null">#{gender},</if><if test="phone!=null">#{phone}</if>)
</insert>
@Test
void insertByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("彭于晏");userInfo.setPassword("123456");userInfo.setAge(18);//userInfo.setPhone("123456");int ret = userInfoMapper.insertByCondition(userInfo);log.info(ret + "被更新");
}

在这里插入图片描述
可以看到,因为 phone 是我们定义增加操作时候的最后一个字段,在这里将 phone 设置为动态的,并且在传递值的时候没有传递 phone,那么在拼接 SQL 的时候 insert into userinfo() values() 中两个括号中一定会是以逗号结尾,那么这样的 SQL 就是不和规则的 SQL,那么如何解决呢?这里就需要用到 <trim> 标签了。

<trim>标签

trim 标签在 MyBatis 中主要用于处理 SQL 语句,以去除多余的关键字、逗号,或者添加特定的前缀和后缀。这在进行选择性插入、更新、删除或条件查询等操作时非常有用。

trim 标签有以下属性:

  • prefix:表⽰整个语句块,以prefix的值作为前缀
  • suffix:表⽰整个语句块,以suffix的值作为后缀
  • prefixOverrides:表⽰整个语句块要去除掉的前缀
  • suffixOverrides:表⽰整个语句块要去除掉的后缀

因为我们这里是语句块末尾出现了多余的逗号,所以我们配置 suffixOverrides 属性来删除多余的逗号。

<insert id="insertByCondition">insert into userinfo<trim prefix="(" suffix=")" suffixOverrides=",">username,`password`,age,<if test="gender!=null">gender,</if><if test="phone!=null">phone</if></trim>values<trim prefix="(" suffix=")" suffixOverrides=",">#{username},#{password},#{age},<if test="gender!=null">#{gender},</if><if test="phone!=null">#{phone}</if></trim>
</insert>

在这里插入图片描述

查询操作

大家在肯定在网上买过手机吧,当我们买手机的时候,往往会加上一些限制条件。

在这里插入图片描述
而这种加上限制条件的查询就可以看成是 select 后面加了 where 语句,但是由于不知道用户需要加上多少查询时候的限制条件,所以这里就可以使用到动态 SQL。

UserInfo selectByCondition(UserInfo userInfo);
<select id="selectByCondition" resultType="com.example.mybatis20240101.model.UserInfo">select * from userinfowhere<if test="username!=null">username=#{username} </if><if test="password!=null">and password=#{password} </if><if test="age!=null">and age=#{age} </if><if test="phone!=null">and phone=#{phone} </if>
</select>
@Test
void selectByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("彭于晏");userInfo.setPhone("34567");log.info(userInfoMapper.selectByCondition(userInfo).toString());
}

在这里插入图片描述
当然这里也会出现问题,就是当第一个 where 子句没有传递值的话,那么 where 子句中就会多一个 and 在开头。

@Test
void selectByCondition() {UserInfo userInfo = new UserInfo();//userInfo.setUsername("彭于晏");userInfo.setPhone("34567");log.info(userInfoMapper.selectByCondition(userInfo).toString());
}

在这里插入图片描述
为了解决问题,可以使用 <trim> 标签删除前面多余的 and:

<select id="selectByCondition" resultType="com.example.mybatis20240101.model.UserInfo">select * from userinfowhere<trim prefixOverrides="and"><if test="username!=null">username=#{username}</if><if test="password!=null">and password=#{password}</if><if test="age!=null">and age=#{age}</if><if test="phone!=null">and phone=#{phone}</if></trim>
</select>

在这里插入图片描述

<where>标签

这里是解决了 where 子句中开头出现多余的 and,如果我们一个限制条件都不加入呢?

@Test
void selectByCondition() {UserInfo userInfo = new UserInfo();//userInfo.setUsername("彭于晏");//userInfo.setPhone("34567");log.info(userInfoMapper.selectByCondition(userInfo).toString());
}

在这里插入图片描述
这样就会出现问题,那么这样如何解决呢?MyBatis 为我们提供了 <where> 标签用来解决查询语句的 where 子句出现的各种问题,包括开头出现的多余的 and 和 where 子句无内容的情况。

<select id="selectByCondition" resultType="com.example.mybatis20240101.model.UserInfo">select * from userinfo<where><if test="username!=null">username=#{username}</if><if test="password!=null">and password=#{password}</if><if test="age!=null">and age=#{age}</if><if test="phone!=null">and phone=#{phone}</if></where>
</select>

在这里插入图片描述
可以看到,当我们 where 子句为空的时候,使用 <where> 标签会自动删除 where 子句,它也可以帮助我们删除多余的 and,下面的报错咱们不管,这时因为我们没加 where 子句,所以就相当于查询整个表,但是我们方法的返回值是 UserInfo,改为列表就可以了。

当 where 子句为空的时候,我们还有一种解决方式,就是自己加上一个 1=1 的条件,这样当我们加的条件为空的时候就不会出现错误。

<select id="selectByCondition" resultType="com.example.mybatis20240101.model.UserInfo">select * from userinfowhere 1=1<trim prefixOverrides="and"><if test="username!=null">username=#{username}</if><if test="password!=null">and password=#{password}</if><if test="age!=null">and age=#{age}</if><if test="phone!=null">and phone=#{phone}</if></trim>
</select>

修改操作

这个修改操作就是前面我们举的一个例子,我们并不知道用户会修改哪些信息,所以我们这里就需要使用到动态 SQL 来解决这个问题。

void updateByCondition(UserInfo userInfo);
<update id="updateByCondition">update userinfo set<if test="password!=null">password=#{password},</if><if test="age!=null">age=#{age},</if><if test="gender!=null">gender=#{gender},</if><if test="phone!=null">phone=#{phone}</if>where<if test="username!=null">username=#{username}</if>
</update>
@Test
void updateByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("小美");userInfo.setPassword("666666");userInfo.setPhone("23456");userInfoMapper.updateByCondition(userInfo);
}

在这里插入图片描述

<set>标签

为了解决 set 中出现的 set 子句中多余的逗号的问题,可以使用 <set> 标签。

在这里插入图片描述

<update id="updateByCondition">update userinfo<set><if test="password!=null">password=#{password},</if><if test="age!=null">age=#{age},</if><if test="gender!=null">gender=#{gender},</if><if test="phone!=null">phone=#{phone}</if></set>    <where><if test="username!=null">username=#{username}</if></where>
</update>

如果 set 子句为空的时候,是会报错的,通过 <set> 标签无法解决,我们应该避免用户 set 输入空的子句。

删除操作

<foreach>标签

当我们想要在删除的时候删除不定数量的条件时,delete from userinfo where name in("小美","小帅"),因为条件的数量是不确定的,所以我们在定义的时候就不知道 where 子句后面有多少个,所以这里我们就需要用到 <foreach> 标签。

<foreach> 标签可以对集合进行遍历,标签具有以下属性:

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串
void deleteByCondition(List<Integer> list);
<delete id="deleteByCondition">delete from userinfowhere id in<foreach collection="list" item="id" open="(" close=")">#{id}</foreach>
</delete>
@Test
void deleteByCondition() {userInfoMapper.deleteByCondition(Arrays.asList(13,18,19,20));
}

在这里插入图片描述

<include>标签

在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码

在这里插入图片描述
我们可以对重复的代码⽚段进⾏抽取,将其通过 <sql> 标签封装到⼀个SQL⽚段,然后再通过
<include> 标签进⾏引⽤。

ArrayList<UserInfo> selectAll();
<sql id="allColumn">id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>
<select id="selectAll" resultType="com.example.mybatis20240101.model.UserInfo">select<include refid="allColumn"></include>from userinfo
</select>
@Test
void selectAll() {log.info(userInfoMapper.selectAll().toString());
}

在这里插入图片描述
这样就可以减少很多重复的代码。

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

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

相关文章

超声波清洗机可以洗些什么东西?质量比较好的超声波清洗机推荐

超声波清洗机只能清洗眼镜吗&#xff1f;不是的&#xff01;超声波清洗机能够清洗的物品远比我们想象的还多&#xff0c;最常见的还是清洗眼镜&#xff0c;毕竟超声波清洗机最常见就是在眼镜店了&#xff0c;很多朋友都喜欢定期都眼镜店里来清洗一下眼镜&#xff0c;这个习惯其…

vivado Revision Control

2020.2 只需要git 管理 prj.xpr 和 prj.srcs/ https://china.xilinx.com/video/hardware/ip-revision-control.html Using Vivado Design Suite with Revision Control https://www.xilinx.com/video/hardware/vivado-design-suite-revision-control.html http://www.xi…

腾讯实验平台基于 StarRocks 构建湖仓底座

作者&#xff1a; 腾讯大数据平台部科学实验中心Tech Lead、专家工程师 马金勇博士 腾讯大数据平台部科学实验中心数据负责人、专家工程师 胡明杰 StarRocks Contributor、腾讯高级工程师 刘志行 在 2022 年&#xff0c;腾讯 A/B Test 团队启动了海外商业化版本 ABetterChoice …

企业网络两层和三层架构部署有何差异

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle OC…

html的全选反选

一、实验题目 html实现选择框的全选和反选 二、实验代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>全选和反选</title></head><body><ul>兴趣爱好</ul><input id"all"…

【AI】 AIOTSummary

智能物联网(AIoT)是2018年兴起的概念,指系统通过各种信息传感器实时采集 各类信息(一般是在监控、互动、连接情境下的),在终端设备、边缘域或云中心 通过机器学习对数据进行智能化分析,包括定位、比对、预测、调度等。智能物联网(AIoT)是2018年兴起的概念,指系统通过…

微软等开源评估ChatGPT、Phi、Llma等,统一测试平台

微软亚洲研究院、中国科学院自动化研究所、中国科学技术大学和卡内基梅隆大学联合开源了&#xff0c;用于评估、分析大语言模型的统一测试平台——PromptBench。 Prompt Bench支持目前主流的开源、闭源大语言模型&#xff0c;例如&#xff0c;ChatGPT、GPT-4、Phi、Llma1/2、G…

基于虚拟机安装centos且远程连接

基于虚拟机安装centos且远程连接 1、安装虚拟机 目前市面上的虚拟机种类有很多&#xff0c;我们可以选择自己熟悉的虚拟机进行安装&#xff0c;我在这里用的虚拟机是VMware。具体的安装过程很简单&#xff0c;一直点击下一步就可以了。因为VMware虚拟机需要激活&#xff0c;所…

AI语音识别模块--whisper模块

1.下载 ffmpeg&#xff0c;挑一个自己电脑系统的版本&#xff0c;下载&#xff0c;如我win64&#xff1a; 地址&#xff1a; Releases BtbN/FFmpeg-Builds GitHub 下载压缩包zip&#xff0c;到本地 解压安装&#xff0c;其实无需安装&#xff0c;只需把对应的目录下的bin&…

【Matlab】在Matlab中安装优化工具yalmip的方法

最近博主想做一些关于多目标优化的问题&#xff0c;因为之前对Matlab有一定经验&#xff0c;所以直接在网上查找了如何在Matlab上实现多目标优化的文献&#xff0c;看到有人提到了yamip&#xff0c;于是博主就试着在Matlab中安装yamip&#xff0c;将其中遇到的问题和一些经验和…

缓存学习实战篇

缓存练习题&#xff08;用户查询操作&#xff09; public List<ShopType> queryAllType() throws JsonProcessingException {//从缓存中查数据String shopTypeJson stringRedisTemplate.opsForValue().get("cache:shopType");//如果缓存命中&#xff0c;if (S…

申请ZeroSSL泛域名域名证书 并部署阿里云测试

安装acme.sh 安装过程中可能会失败 多试几次就会成功 wget -O - https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m 你的邮箱gmail.com安装完成后重新加载 Bash&#xff1a; source ~/.bashrc然后也可以开启自动更…

客户端请求服务器的步骤

当我们在浏览器地址栏输入’http://www.xxx.com/api/xxx"时&#xff0c;客户端是如何找到服务器并发送请求的&#xff1f; 1.先找到服务器 a.检测浏览器缓存有没有缓存该域名对应的IP地址&#xff0c;有则通过IP地址取找服务器。 b.检测本地的hosts文件&#xff0c;是否有…

FPGA 高端项目:基于 SGMII 接口的 UDP 协议栈,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的以太网方案本协议栈的 1G-UDP版本本协议栈的 10G-UDP版本本协议栈的 25G-UDP版本1G 千兆网 TCP-->服务器 方案1G 千兆网 TCP-->客户端 方案10G 万兆网 TCP-->服务器客户端 方案 3、该UDP协议栈性能4、详细设计方案设…

NX二次开发PK获取对象类型

PK_ENTITY_ask_class(),获取对象类型建议用这个函数&#xff0c;比较通用&#xff0c;包含所有对象类型&#xff0c;可以替代UF_MODL_ask_edge_type(),UF_MODL_ask_body_type(),UF_MODL_ask_face_type()等函数 PK_ENTITY_t entity; PK_CLASS_t PK_TYPE; PK_ENTITY_ask_class(e…

openAI API key不需要中转,自己就可以使用正版

很多小伙伴因为不知道怎么使用原版&#xff0c;用的都是国内套壳的&#xff0c;国内套壳的有些价格不合适&#xff0c;如何是3.5的话只需要绑定虚拟信用卡就可以使用 想使用openai API key4.0的话你需要先开通ChatGPTplus&#xff0c;在绑定openai API key&#xff0c;绑定ope…

Spring事务失效场景之类内部方法调用及解决方案

一、背景 在日常开发中&#xff0c;经常有需要使用事务来保证数据一致性的情况。简单点的话直接在方法上面加Transactional注解就可以了。 但这样存在一个问题&#xff0c;在整个业务方法层面加注解会把很多并不需要归入事务的操作也归入到了事务里面&#xff0c;这样会可能会…

算法第十七天-构造有效字符串的最少插入数

构造有效字符串的最少插入数 题目要求 解题思路 考虑abc的个数 假设答案有n个"abc"组成&#xff0c;那么需要插入的字符个数为 3 ∗ n − l e n ( s ) 3*n - len(s) 3∗n−len(s)。 对于相邻的两个字符x和y&#xff08;x在y左侧&#xff09;&#xff1a; 如果 x…

OCR字符识别:开始批量识别身份证信息

身份证信息批量识别OCR是一项解决方案&#xff0c;它能够将身份证照片打包成zip格式或通过URL地址进行提交&#xff0c;并能够识别照片中的文本信息。最终&#xff0c;用户可以将识别结果生成为excel文件进行下载。 API接口功能&#xff1a; 1. 批量识别&#xff1a;支持将多…

【面试合集】2.说说微信小程序的生命周期函数有哪些?

面试官&#xff1a;说说微信小程序的生命周期函数有哪些&#xff1f; 一、是什么 跟vue、react框架一样&#xff0c;微信小程序框架也存在生命周期&#xff0c;实质也是一堆会在特定时期执行的函数 小程序中&#xff0c;生命周期主要分成了三部分&#xff1a; 应用的生命周期…