Mybatis进阶——动态SQL

         动态SQL 是Mybatis的强大特性之一,能够完成不同条件下的不同SQL拼接,可以参考官方文档:动态 SQL_MyBatis中文网

         xml文件内容如下:

<?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.mybatis.model.UserInfo"></mapper>

1. <if> 标签

        在注册用户的时候,可能会有这样一个问题,如下图所示:

         注册分为两种字段:必填字段和非必填字段,那如果在添加用户的时候有不确定的字段传入,程序应该如何实现呢 ,这个时候就需要使用 动态标签 来判断了,比如添加的时候性别 gender 为非必填字段,具体实现如下:

        userInfoMapper接口代码:

@Mapper
public interface UserInfoMapper {Integer insertByCondtion(UserInfo userInfo);
}

        xml配置文件:

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

        测试类代码:

@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid insertByCondtion() {UserInfo userInfo = new UserInfo();userInfo.setUsername("zhaoliu");userInfo.setPassword("zhaoliu");userInfo.setAge(15);
//        userInfo.setGender(1);userInfoMapper.insertByCondtion(userInfo);}
}

        表中gender属性默认是0,如图:

        当我们不指定gender值时,直接执行上面代码,结果如下: 

          当指定gender的值时,代码如下:

@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid insertByCondtion() {UserInfo userInfo = new UserInfo();userInfo.setUsername("zhaoliu");userInfo.setPassword("zhaoliu");userInfo.setAge(15);userInfo.setGender(1);userInfoMapper.insertByCondtion(userInfo);}
}

        结果如下:

         这就是动态SQL语句,想给他传值就变成所传的值,不想给他传值会有默认值0。也就变成复杂SQL了,之前博客写的那些都是简单标签,如果没有<if> 标签,单凭借之前的那些简单SQL,是不能做到上面这样的功能的。

        上面的SQL语句也可以写成注解的形式,但是不推荐,其代码如下:

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

        可以看出注解的形式非常复杂;

2. <trim> 标签

        之前的插入用户功能,只是一个gender字段可能是选填项,如果有多个字段,一般考虑使用结合标签,对多个字段都采取动态生成的方式

        标签中有如下属性:

prefix:表示整个语句块,以 prefix 的值作为前缀。

suffix:表示整个语句块,以 suffix 的值作为后缀。

prefixOverrides:表示整个语句块要去除掉的前缀。

suffixOverrides:表示整个语句块要去除掉的后缀。

         把username设置默认为admin,代码如下:

DROP DATABASE IF EXISTS mybatis_test;CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;-- 使用数据数据
USE mybatis_test;-- 创建表[用户表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL DEFAULT 'admin' COMMENT '默认admin',`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'shangjialu', '111111', 18, 1, '15809211621' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'shenmengyao', '222222', 18, 2, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'yuanyiqi', '333333', 18, 2, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zuojinyuan', '555555', 18, 2, '18612340004' );

        Mapper.xml的内容如下:

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

         把setUsername的方法注释掉,测试类代码如下:

 @Testvoid insertByCondtion() {UserInfo userInfo = new UserInfo();
//        userInfo.setUsername("zhaoliu");userInfo.setPassword("zhoushiyu");userInfo.setAge(15);userInfo.setGender(1);userInfoMapper.insertByCondation(userInfo);}

        会出现如下的报错信息; 

         使用 <trim>标签,代码如下:

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

        结果如下:

 

1、基于 prefix 配置,开始部分加上 ( 

2、基于 suffix 配置,结束部分加上 )

3、多个组织的语句都以 " , " 开头,拼接好的字符串还会以 " , " 开头,会基于 suffixOverrides 配置去掉开头的一个 " , " (prefixOverrides则相反,是结尾)

4、注意 < if test="username != null"> 中的 username 是传入对象的属性

3. <where> 标签

        一般网页都会有筛选条件,系统会根据我们的筛选条件,动态组装 where 条件。

         UserInfoMapper接口代码:

@Mapper
public interface UserInfoMapper {List<UserInfo> queryUserByCondition(UserInfo userInfo);
}

          xml配置信息如下:

  <select id="queryUserByCondition" resultType="com.example.zxslzw_mybaties.model.UserInfo">select * from userinfo where<if test="age != null">age = #{age}</if><if test="gender != null">and gender = #{gender}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></select>

        测试类代码:

 @Testvoid queryUserByCondition() {UserInfo userInfo = new UserInfo();
//        userInfo.setAge(15);userInfo.setGender(2);userInfo.setDeleteFlag(0);System.out.println(userInfoMapper.queryUserByCondition(userInfo));}

         把设置age给注释掉,是可以成功运行的,但注释掉后,就会报错,报错信息如下:

         现在给XML内容加上<trim>标签,内容如下: 

 <select id="queryUserByCondition" resultType="com.example.zxslzw_mybaties.model.UserInfo">select * from userinfo whereselect * from userinfo<trim prefix="where" prefixOverrides="and"><if test="age != null">age = #{age}</if><if test="gender != null">and gender = #{gender}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></trim></select>

        结果如下:

        Mybatis提供了<where>标签,所以可以使用<where>标签,xml内容如下 :

 <select id="queryUserByCondition" resultType="com.example.zxslzw_mybaties.model.UserInfo">select * from userinfo<where><if test="age != null">and age = #{age}</if><if test="gender != null">and gender = #{gender}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></where></select>

        可以看到,<where>标签代替了<trim>标签的prefix和prefixOverrides,运行刚才的测试类代码,运行结果如下:

        注意:<where> 只会在子元素有内容的情况下才插入where子句,而且会自动去除子句开头(或结尾)的and或or。上面标签虽然可以使用<trim prefix="where" prefixOverrides="and">替换,但是此种情况下,当子元素都没有内容时,where 关键字也会保留

4. <set> 标签

        SQL语句:

update userinfo set username = ?, age = ?, delete_flag = ? where id = ?

         UserInfoMapper接口代码:

@Mapper
public interface UserInfoMapper {Integer updateUserByCondition(UserInfo userInfo);
}

         xml内容如下:(使用<trim>标签

  <update id="updateUserByCondition">update userinfo<trim prefix="set" prefixOverrides=","><if test="username != null">username = #{username}</if><if test="age != null">,age = #{age}</if><if test="deleteFlag != null">,delete_flag = #{deleteFlag}</if></trim>where id = #{id}</update>

        测试类代码:

  @Testvoid updateUserByCondition() {UserInfo userInfo = new UserInfo();userInfo.setId(5);userInfo.setUsername("wanger");userInfo.setAge(18);userInfo.setDeleteFlag(0);userInfoMapper.updateUserByCondition(userInfo);}

        运行测试类,结果如下:

起初数据库表信息:

之后数据库表信息:

        上面使用<trim>标签,针对update(改)可以使用<set>标签

        改变xml内容:(使用<set>标签)

<update id="updateUserByCondition">update userinfo<set><if test="username != null">username = #{username}</if><if test="age != null">,age = #{age}</if><if test="deleteFlag != null">,delete_flag = #{deleteFlag}</if></set>where id = #{id}</update>

        其中where关键字可以使用<where>标签,但是因为where后的id是肯定必须要有的,可以直接写上;

      测试类代码如下:

 @Testvoid updateUserByCondition() {UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setUsername("zhongxia");userInfo.setAge(18);userInfo.setDeleteFlag(0);userInfoMapper.updateUserByCondition(userInfo);}

        结果如下: 

        可以看到,<set>标签代替了<trim prefix="set" prefixOverrides=",">,说明动态SQL语句中插入set关键字,并且会删掉额外的逗号。(用于update语句中) 

5. <foreach> 标签

        对集合进行遍历时可以使用该标签。标签有如下属性:

1、collection:绑定方法参数中的集合,如 List、Set、Map或数组对象。

2、item:遍历时的每一个对象。

3、open:语句块开头的字符串。

4、close:语句块结束的字符串。

5、separator:每次遍历之间间隔的字符串。

        原本SQL语句::

delete from userinfo where id in (1, 2, 3, 4)

          UserInfoMapper接口代码如下:

@Mapper
public interface UserInfoMapper {Integer batchDelete(List<Integer> ids);
}

          xml内容如下:

<delete id="batchDelete">delete from userinfo where id in<foreach collection="ids" open="(" close=")" item="id" separator=",">#{id}</foreach></delete>

        测试代码如下:

 @Testvoid batchDelete() {List<Integer> ids = Arrays.asList(new Integer[]{1, 5});userInfoMapper.batchDelete(ids);}

        结果如下:

        我们不仅可以批量删除,也可以批量插入。 

6. <include> 标签

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

         我们可以对重复的片段进行抽取,将其通过<sql>标签封装到一个SQL片段,然后再通过<include>标签进行引用。

<sql>:定义可重用的SQL片段。

<include>:通过属性refid,指定包含的SQL片段。

 <sql id="allColumn">id, username, age, gender, phone, delete_falg, create_time, update_time</sql><select id="queryAllUser" resultType="com.example.mybatis.model.UserInfo">select <include refid="allColumn"></include>  from userinfo</select><select id="queryById" resultType="com.example.mybatis.model.UserInfo">select <include refid="allColumn"></include> from userinfo where id=#{id}</select>

         通过<include>标签,去除掉了重复出现的代码。

ps:本文就写到这里了,如果对你有所帮助的话,就请一键三连哦!!!

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

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

相关文章

uniapp/uniapp x总结

uni-app组成和跨端原理 上图所诉 App的渲染引擎&#xff1a;同时提供了2套渲染引擎&#xff0c;.vue页面文件由webview渲染&#xff0c;原理与小程序相同&#xff1b;.nvue页面文件由原生渲染&#xff0c;原理与react native相同。开发者可以根据需要自主选择渲染引擎。 uniapp…

52.给定一个整数 n,实现一个算法返回 n 皇后不同的解决方案的数量

52. N-Queens II 题目 n皇后问题是指将n个皇后放置在一个nn的棋盘上,使得任意两个皇后不在同一行、同一列或同一对角线上。 给定一个整数 n,返回 n 皇后问题不同的解法数量。 示例: 输入: 4 输出: 2 解释: 4皇后问题有如下两个不同的解法: [ [“.Q…”, // 解法 1 “……

sqli-labs靶场通关攻略(36-40关)

第36关&#xff08;宽字节注入&#xff08;Bypass MySQL Real Escape String&#xff09;&#xff09; 查数据库 ?id-1%df%27%20union%20select%202,database(),3%20-- 查表 ?id-1%df union select 1,group_concat(table_name),3 from information_schema.tables where tab…

Python青少年简明教程:列表(List)、元组(tuple)和字典(dict)

Python青少年简明教程&#xff1a;列表&#xff08;List&#xff09;、元组&#xff08;tuple&#xff09;和字典&#xff08;dict&#xff09; 在Python中&#xff0c;列表&#xff08;List&#xff09;、元组&#xff08;Tuple&#xff09;和字典&#xff08;Dict&#xff09…

Ubuntu下部署Hadoop集群+Hive(三)

Hive部署 准备环境 apache-hive-4.0.0-bin.tar.gz、mysql-connector-j-8.1.0.jar 如果是离线安装的话&#xff0c;使用mysql-8.0.34-1.el7.x86_64.rpm-bundle.tar&#xff0c;在线安装的话则不用&#xff1b; hive下载地址&#xff1a;Index of /hive (apache.org) mysql …

机械学习—零基础学习日志(如何理解概率论9)

大数定律与中心定律 来看一道习题&#xff1a; 这个题目看看&#xff0c;应该是什么呢~下一章来看看解析~ 《概率论与数理统计期末不挂科|考研零基础入门4小时完整版&#xff08;王志超&#xff09;》学习笔记 王志超老师 &#xff08;UP主&#xff09;

vue3 + ElImage + nodejs 集成了看板娘(UI原生开发达99%)的响应式BLOG(个人博客)。

一、想要我的屎山代码&#xff0c;可以私聊我哟 访问地址&#xff0c;欢迎访问&#xff08;访问效果更佳&#xff09; ☂ 被你发现了&#xff01;&#xff5c; snows_ls BLOGhttp://124.223.41.220/ 欢迎互挂友链 二、做了个啥 1、看板娘&#xff08;看效果好吧&#xff09;…

【数据结构】线性表的顺序表示(顺序表的定义和基本操作)

计算机考研408-数据结构笔记本之——第二章 线性表 2.2 线性表的顺序表示&#xff08;顺序表的定义和基本操作&#xff1a;初始化/插入/删除/查找&#xff09; 2.2.1 顺序表的定义 1.定义 顺序表是线性表的顺序存储。 所谓顺序存储&#xff0c;就是把逻辑上相邻的元素存储在物…

C++ 设计模式——享元模式

C 设计模式——享元模式 C 设计模式——享元模式1. 主要组成成分2. 享元模式内部状态3. 享元模式外部状态4. 逐步构建享元模式4.1 抽象享元类定义4.2 具体享元类实现4.3 享元工厂类实现4.4 主函数 5. 享元模式 UML 图享元模式 UML 图解析 6. 享元模式的优点7. 享元模式的缺点8.…

Linux驱动学习之中断与等待队列

本篇分为设备树部分和API接口部分 设备树 想要使用中断&#xff0c;设备树中需要有两个属性&#xff1a; interrupts // 表示要使用哪一个中断, 中断的触发类型等等。 interrupt-parent // 这个中断要接到哪一个设备去? 即父中断控制器是谁 父中…

趣味算法------拯救阿拉德大陆

目录 ​编辑 题目描述&#xff1a; 思路解析&#xff1a; 具体代码&#xff1a; 总结&#xff1a; 题目描述&#xff1a; 此时一批勇士也随之而来&#xff0c;但其能力也是参差不齐&#xff0c;我们需要挑选出最优秀的勇士来守护这片大陆。每位勇士都有属于自己的编号&am…

JobSchedulerService.setRequiresCharging需充电且电量大于90%才触发的现象

一、摘要 从源码看原生JobSchedulerService.setRequiresCharging 的特性&#xff0c;该特性竞品机器华为、Oppo也是如此。 1、应用处于前台可见&#xff0c;满足充电条件&#xff0c;立刻触发 2、应用处于后台不可见&#xff0c;需要设备连接USB或AC且电量大于90%&#xff0…

挂个人-CSDN Java优秀内容博主rundreamsFly抄袭

事件起因 今天点开自己的CSDN博客&#xff0c;发现给我推了一篇文章抄袭我自己昨天18点发的文章。 就是这篇&#xff0c;一字不差&#xff0c;博主昵称是&#xff1a;rundreamsFly&#xff0c;账号是rundreams。 抄袭者文章 发布于2024-8-26 19:37:41秒&#xff0c;比我发布…

C的温故而知新:位操作(C Primer Plus第十五章)

第十五章&#xff1a;位操作 这一章的篇幅不是很长&#xff0c;但既然能单独作为一章来讲的话&#xff0c;应该蛮重要的&#xff0c;但是我貌似没有总结出多少需要注意、加强记忆的东西&#xff0c;可见在JAVA的日常开发过程中基本不太遇见有关位操作的内容&#xff0c;所以我…

FSQ26信号分析仪RS FSU26 20HZ-26.5G频谱分析仪

罗德与施瓦茨Rohde & Schwarz FSQ26信号分析仪&#xff0c;20 Hz - 26.5 GHz ​R&S FSQ26 信号分析仪集两种仪器于一身。它提供高达 120 MHz 解调带宽的信号分析&#xff0c;并具有高端频谱分析仪的动态范围。 频率范围&#xff1a;20 Hz 至 26.5 GHz 高端频谱分析仪…

神经网络—卷积层

1.讲解 Conv2d out_channels 参数为2时&#xff0c;会生成两个卷积核&#xff0c;分别与输入进行卷积。得到的两个输出为输出 新生成的卷积核和原来的卷积核不一定相同 in_channels (int) – Number of channels in the input image out_channels (int) – Number of channels…

ARM32开发——(六)GPIO_USART通信原理

1. 串行通信和并行通信 1.1 串行通信 串行通信是一种数据传输的方式&#xff0c;它是指将数据按照一位一位的顺序依次发送和接收&#xff0c;常用于远距离通信、嵌入式系统和低带宽传输场景下。串行通信相对于并行通信而言&#xff0c;只需要传输一条数据线&#xff0c;相对简…

一文了解机器学习顶会ICML 2024的研究热点

对人工智能研究领域前沿方向的跟踪是提高科研能力和制定科研战略的关键。本文通过图文并茂的方式介绍了ICML 2024的研究热点&#xff0c;帮助读者了解和跟踪机器学习和人工智能的前沿研究方向。本推文的作者是许东舟&#xff0c;审校为邱雪和黄星宇。 1 会议介绍 ICML&#x…

运放阻抗和噪声(同相放大器的输入/输出阻抗 + 电压跟随器阻抗 + 噪声 +信噪比)

2024-8-27&#xff0c;星期一&#xff0c;21:03&#xff0c;天气&#xff1a;阴雨&#xff0c;心情&#xff1a;晴。培训终于结束啦&#xff0c;开始轮岗了&#xff0c;看了两天PPT&#xff0c;加油加油&#xff0c;继续学习。 今天继续学习第六章运算放大器&#xff0c;主要学…

一文带你从零到实战,学会gcc和Makefile,多文件编译神器的使用与编写

目录&#xff1a; 目录&#xff1a; 一、什么是Makefile 1.1 makefile的作用&#xff1a; 1.2 makefile的基本组成&#xff1a; 二、Linux编译过程&#xff1a; 2.1 linux编译过程: 2.1.1 预处理&#xff08;Preprocessing&#xff09; 2.1.2 编译&#xff08;Compilation&am…