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

MyBatis动态SQL

还不了解MySQL的可以看我这篇文章:

MyBatis入门:快速搭建数据库操作框架 + 两种增删改查的方法(CRUD)-CSDN博客

动态 SQL 是Mybatis的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接

官方文档:动态 SQL_MyBatis中文网

创建相关数据库

-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;-- 使用数据数据
USE mybatis_test;-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`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() ON UPDATE now(),PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

一、<if>标签

在注册⽤⼾的时候,可能会有这样⼀个问题,如下图所⽰:

注册分为两种字段:必填字段和⾮必填字段,那如果在添加⽤⼾的时候有不确定的字段传⼊,程序应

该如何实现呢?

这个时候就需要使⽤动态标签来判断了,⽐如添加的时候性别 gender 为⾮必填字段,具体实现如

下:

@Mapper
public interface UserInfoXMLMapper {Integer insertUserByCondition(UserInfo userInfo);}
<?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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><insert id="insertUserByCondition">insert into user_info (username,password,age,<if test="gender != null">gender</if>)values (#{username},#{password},#{age},<if test="gender != null">#{gender}</if>)</insert></mapper>

单元测试:

测试纯在gender的情况:

@SpringBootTest
class UserInfoXMLMapperTest {@AutowiredUserInfoXMLMapper userInfoXMLMapper;@Testvoid insertUserByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("王麻子");userInfo.setPassword("123");userInfo.setAge(22);userInfo.setGender(0);userInfoXMLMapper.insertUserByCondition(userInfo);}
}

结果:

测试不存在gender的情况:

@SpringBootTest
class UserInfoXMLMapperTest {@AutowiredUserInfoXMLMapper userInfoXMLMapper;@Testvoid insertUserByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("王麻子");userInfo.setPassword("123");userInfo.setAge(22);//userInfo.setGender(0);userInfoXMLMapper.insertUserByCondition(userInfo);}
}

需要处理一下sql中的“,”

再次执行:

这样就可以了

那如果所有的都是非必传字段呢?

<?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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><insert id="insertUserByCondition">insert into user_info (<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>
</mapper>

测试所有字段都传的情况下:

这个时候我又不穿gender:

那我们将sql中的“,”全部放在前面:

<?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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><insert id="insertUserByCondition">insert into user_info (<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>
</mapper>

那我再不传username呢?

测试

这个时候就需要用另一个注解了:

二、<trim>标签

之前的插⼊⽤⼾功能,只是有⼀个 gender 字段可能是选填项,如果有多个字段,⼀般考虑使⽤标签结

合标签,对多个字段都采取动态⽣成的⽅式。

标签中有如下属性:

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

那么我将“,”移到字段末尾:

<mapper namespace="com.Li.mybatis.demo.mapper.UserInfoXMLMapper"><insert id="insertUserByCondition">insert into user_info<trim prefix="(" suffix=")" suffixOverrides=","><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=")" suffixOverrides=","><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>
</mapper>

测试不加gender的情况:

@SpringBootTest
class UserInfoXMLMapperTest {@AutowiredUserInfoXMLMapper userInfoXMLMapper;@Testvoid insertUserByCondition() {UserInfo userInfo = new UserInfo();userInfo.setUsername("王麻子");userInfo.setPassword("123");userInfo.setAge(22);
//        userInfo.setGender(0);userInfoXMLMapper.insertUserByCondition(userInfo);}
}

结果:

trim就帮我们处理掉了末尾的","

在以上 sql 动态解析时,会将第⼀个部分做如下处理:

  • 基于 prefix 配置,开始部分加上 (
  • 基于 suffix 配置,结束部分加上 )
  • 多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于suffixOverrides 配置去掉最后⼀个 ,
  • 注意 <if test="username !=null"> 中的 username 是传⼊对象的属性

三、<where>标签

看下⾯这个场景, 系统会根据我们的筛选条件, 动态组装where 条件

这种如何实现呢?

接下来我们看代码实现:

需求: 传⼊的⽤⼾对象,根据属性做where条件查询,⽤⼾对象中属性不为 null 的,都为查询条件. 如username 为 "a",则查询条件为 where username="a"

原有sql:

接口定义:

@Mapper
public interface UserInfoXMLMapper {List<UserInfo> queryByCondition(UserInfo userInfo);
}

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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><select id="queryByCondition" resultType="com.Li.mybatis.demo.model.UserInfo">SELECT * FROM user_info<where><if test="age != null">age = #{age} and</if><if test="deleteFlag != null">delete_flag = #{deleteFlag} and</if></where></select>
</mapper>

测试用例:

@SpringBootTest
class UserInfoXMLMapperTest {@AutowiredUserInfoXMLMapper userInfoXMLMapper;@Testvoid queryByCondition() {UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setDeleteFlag(0);userInfoXMLMapper.queryByCondition(userInfo);}
}

当age和deleteFlag都有值:

如果我们不写deleteFlag:

where不会帮我们取出末尾的and 或者 or , 但是最 前面 的or 和 and 可以,测试:

<?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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><select id="queryByCondition" resultType="com.Li.mybatis.demo.model.UserInfo">SELECT * FROM user_info<where><if test="age != null">and age = #{age}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></where></select>
</mapper>

结果:

所以where 是可以帮我们取出前面的 and 或者 or的

那么如果我一个都不写:

💡

<where> 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或OR

以上标签也可以使⽤ <trim prefix="where" prefixOverrides="and"> 替换, 但是此种

情况下, 当⼦元素都没有内容时, where关键字也会保留

四、<set>标签

需求: 根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤标签来指定动态内容.

接⼝定义: 根据传⼊的⽤⼾ id 属性,修改其他不为 null 的属性

源SQL:

UPDATE user_info set username = 'zzz', age = 20, delete_flag = 1 WHERE id = 13

定义接口:

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

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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><update id="updateUserByCondition">UPDATE user_info<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 = 13</where></update>
</mapper>

单元测试:

如果不写deleteFlag(末尾选项):

结果:

注意age后面是有“,”的

如果一个元素都没有:

set就会不存在,但是sql肯定就错误了,所以set也做不了什么,过多的东西

💡

<set> :动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号. (⽤于update语句中)

五、<foreach>标签

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

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

需求: 根据多个userid, 删除⽤⼾数据

DELETE FROM user_info WHERE id IN (21,22,23)

写接口:

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

xml:

<?xml version="1.0" encoding="UTF-8"?><?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.Li.mybatis.demo.mapper.UserInfoXMLMapper"><delete id="batchDelete">DELETE FROM user_info WHERE id IN <foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete></mapper>

测试用例:

@SpringBootTest
class UserInfoXMLMapperTest {@AutowiredUserInfoXMLMapper userInfoXMLMapper;@Testvoid batchDelete() {List<Integer> ids = new ArrayList<>();ids.add(19);ids.add(24);ids.add(25);userInfoXMLMapper.batchDelete(ids);}
}

结果:

六、<include>标签

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

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

  • <sql> :定义可重⽤的SQL⽚段
  • <include> :通过属性refid,指定包含的SQL⽚段
<?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.Li.mybatis.demo.mapper.UserInfoXMLMapper">
<!--    假设这是一串冗余的代码--><sql id="deleteUser">DELETE FROM user_info</sql><delete id="batchDelete"><include refid="deleteUser"></include>WHERE idIN <foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete></mapper>

相当于通过sql定义字符串,可以通过include标签通过id指定对应的字符串

上面的内容也标签也可以用,通过<script></script> 标签括起来就可以,但是不推荐,因为看着非常乱,就容易出错

相关文章:

  • go并发编程| channel入门
  • 2024 CKA模拟系统制作 | Step-By-Step | 15、查看Pod日志
  • ICECEPSS 2025:节能环保与社会治理的融合之道
  • 百度之星2024 初赛第一场 补给
  • 基于大模型的重度膝关节骨关节炎全流程预测与治疗方案研究
  • Elasticsearch集群管理的相关工具介绍
  • 晶振频率稳定性:5G 基站与航天设备的核心竞争力
  • 5G-A时代与p2p
  • linux创建虚拟网卡和配置多ip
  • Python进阶【四】:XML和JSON文件处理
  • Spring官方的在线教程也可以用中文观看了
  • pom.xml 文件中配置你项目中的外部 jar 包打包方式
  • Sentieon项目文章 | 社区努力识别和纠正蛋白质基因组研究中标签错误的样本
  • 用户隐私如何在Facebook的大数据中得到保护?
  • Windows 中禁止在桌面放置文件以保持桌面整洁
  • 如何全面了解支付宝生态帝国,有何启发?
  • 经典SQL查询问题的练习第一天
  • C语言中野指针问题
  • 前端面试题-HTML篇
  • 「卫星百科」“绿色守卫”高分六号
  • 百度网盘怎么做网站/湖北seo公司
  • wordpress新增目录/seo官网优化怎么做
  • 厦门网站建设seo/完善的seo网站
  • 东莞建设网站的公司/长尾关键词挖掘工具
  • 网站美工做图推荐/排名
  • 网站建设公司彩铃/怎样推广小程序平台