一、应用场景MyBatis 的动态 SQL是指根据不同的条件动态拼接生成 SQL 语句的能力。它的最大优势是避免写多个 XML 映射语句、避免 SQL 冗余、提升代码复用性和可维护性。示例1用户可以通过勾选框勾选不同的数据进行批量删除此时delete from xxx_table where id in (a, b, c, d, ......)in后面括号中的数据就是动态的。示例2用户搜索功能查询条件不确定常用于搜索/筛选二、使用方式XML 标签MyBatis 动态 SQL 主要通过XML 配置文件中的标签来实现核心标签如下标签作用if条件判断choose / when / otherwise类似 Java 中的 if-else if-elsewhere自动加上WHERE并避免多余的 AND/ORset用于UPDATE自动去除最后的逗号foreach用于遍历集合常见于 IN、批量插入trim自定义前缀、后缀、去掉前后符号等2-1、if标签示例ListCar selectByMutiConditions(Param(brand) String brand, Param(guidePrice) Double guidePrice, Param(carType) String carType);select idselectByMutiConditions resultTypecar select * from t_car where 11 /* 1. if标签中test属性是必须的值表达式false/true 2. test属性可以使用的是 使用了Param标签就用Param标签指定的参数名 没有使用Param标签就用param1, param2, param3, arg0, arg1, arg2... 当使用了pojo就用pojo中的属性名 3. 在mybatis的动态sql中不能使用只能使用and */ if testbrand ! null and brand ! and brand like %#{brand}% /if if testguidePrice ! null and guidePrice ! and guidePrice #{guidePrice} /if if testcarType ! null and carType ! and carType #{carType} /if /select【注意点】1. if标签中test属性是必须的值表达式false/true2. test属性可以使用的是使用了Param标签就用Param标签指定的参数名没有使用Param标签就用param1, param2, param3, arg0, arg1, arg2...当使用了pojo就用pojo中的属性名3. 在mybatis的动态sql中不能使用只能使用and。4、为了防止有部分条件不成立的时候where后面直接拼接了and需要加上112-2、where标签它的作用是在生成 SQL 语句时自动去掉首个条件前多余的AND或OR当有条件时自动加上WHERE关键字当没有任何条件时不会生成WHERE子句【注意】where标签只对内容中出现的第一个 AND/OR进行清理建议把每个if条件前都加上AND它会自动清理第一个多余的。示例2-3、trim标签在 MyBatis 中trim是一个功能非常强大的动态 SQL 标签它可以灵活地控制前缀prefix开头加什么后缀suffix结尾加什么前缀去除prefixOverrides去掉开头多余的关键字比如AND/OR/,后缀去除suffixOverrides去掉结尾多余的内容比如,你可以把trim看成where和set的“底层基础版本”功能更灵活。1、常见属性说明属性名说明prefix给内容加上前缀比如WHERE、SETsuffix给内容加上后缀prefixOverrides去除内容前面多余的前缀如多余的AND、ORsuffixOverrides去除内容最后多余的后缀如多余的,【注意】它们都是在整体 trim 内容拼接完毕后一次性处理整个SQL 片段的前缀和后缀示例 1动态 WHERE 条件代替whereselect idselectUser parameterTypeUser resultTypeUser SELECT * FROM user trim prefixWHERE prefixOverridesAND |OR if testusername ! null AND username #{username} /if if testgender ! null AND gender #{gender} /if /trim /select效果如果 username ! null 且 gender nullSELECT * FROM user WHERE username Tom自动去掉多余的AND和where效果一样但更灵活你也可以换成 OR。示例 2动态更新字段代替setupdate idupdateUser parameterTypeUser UPDATE user trim prefixSET suffixOverrides, if testusername ! null username #{username}, /if if testgender ! null gender #{gender}, /if /trim WHERE id #{id} /update效果如果 username Tom, gender nullUPDATE user SET username Tom WHERE id 1自动去掉最后多余的逗号,示例 3完全自定义的 SQL 拼接trim prefix( suffix) suffixOverrides, foreach collectionids itemid #{id}, /foreach /trim输出示例(1, 2, 3)2-4、set标签set标签的作用是自动添加SET关键字自动去除多余的结尾逗号,与if标签组合使用实现根据条件动态更新字段目的希望更新的时候只更新不为null的字段其余字段不动1、基本语法结构update idupdateUser parameterTypeUser UPDATE user set if testusername ! null username #{username}, /if if testemail ! null email #{email}, /if if testage ! null age #{age}, /if /set WHERE id #{id} /update2、执行逻辑过程假设只传了username和ageemail是 null。MyBatis 会生成这样的 SQLUPDATE user SET username ?, age ? WHERE id ?注意✅ 自动添加了SET✅ 自动移除了末尾多余的,3、和trim的关系set本质上就是trim的封装版本等价于trim prefixSET suffixOverrides, ... /trimset是trim的语法糖功能几乎一样只是更简洁。也就是说如果你希望自定义更多行为如不使用SET、用别的关键字可以改用trim标签。4、什么时候必须用trimset只适用于UPDATE的SET关键字但trim更通用场景1自定义前缀/后缀set做不到!-- 给 WHERE 条件加前缀 AND -- select idselectByCondition SELECT * FROM t_car trim prefixWHERE prefixOverridesAND |OR if testbrand ! nullAND brand #{brand}/if if testcolor ! nullAND color #{color}/if /trim /select !-- 生成的 SQL自动去掉第一个 AND -- SELECT * FROM t_car WHERE brand ? AND color ?场景2INSERT 的 VALUES 括号insert idinsertSelective INSERT INTO t_car trim prefix( suffix) suffixOverrides, if testbrand ! nullbrand,/if if testcolor ! nullcolor,/if /trim trim prefixVALUES ( suffix) suffixOverrides, if testbrand ! null#{brand},/if if testcolor ! null#{color},/if /trim /insert !-- 生成的 SQL -- INSERT INTO t_car (brand, color) VALUES (?, ?)2-5、choose、when、otherwiseMyBatis 中的choose标签是用来实现类似 Java 中 if-else if-else 结构的动态 SQL 分支选择语句非常适合你有多个条件分支但只想执行其中一个的情况。说明choose类似于 Java 的switch或if-else if-elsewhen类似于if/else ifotherwise类似于else最后的默认分支可以省略如果你需要互斥条件只走其中一个分支就用choose如果是叠加条件多个都可能生效就用多个if。1、 作用choose是 MyBatis 提供的一个逻辑分支标签用来表示如果满足第一个条件就执行它否则判断第二个条件……都不满足则执行默认分支。它的结构和 Java 中的if ... else if ... else是一致的if (a ! null) { // ... } else if (b ! null) { // ... } else { // default }在 MyBatis 中写法如下choose when testa ! null ... /when when testb ! null ... /when otherwise ... /otherwise /choose2、使用示例例子根据传入的条件查询用户select idfindUser parameterTypemap resultTypeUser SELECT * FROM user where choose when testid ! null id #{id} /when when testusername ! null username #{username} /when otherwise gender male /otherwise /choose /where /select3、执行逻辑假设传入参数是MapString, Object param new HashMap(); param.put(username, Tom);生成的 SQL 就是SELECT * FROM user WHERE username Tom如果传入参数是param.put(id, 123); param.put(username, Tom);优先满足第一个条件SELECT * FROM user WHERE id 123如果两个都没传则使用otherwiseSELECT * FROM user WHERE gender male4、几点注意事项特性说明choose内只能选中一个when被执行只执行第一个匹配成功的whenotherwise是可选的不写也可以多个when的顺序很重要从上往下匹配匹配到就停2-6、foreach标签MyBatis 中的foreach标签是动态 SQL 中非常重要的一个标签主要用于遍历集合如List、数组、Map生成一段重复的 SQL 语句特别适合用于批量插入、批量删除、IN (...)条件语句1、 的核心作用用来遍历集合如List、数组、Map在 SQL 中动态生成重复片段比如id IN (1, 2, 3)多行VALUES插入多个字段拼接2、常见属性说明属性名说明collection要遍历的集合名如list、array、map等item遍历过程中每一项的变量名index当前项的下标可选open开始拼接的前缀如(close拼接结束的后缀如)separator每项之间的分隔符如,3、经典使用场景(1).IN (...)查询select idselectByIds parameterTypelist resultTypeUser SELECT * FROM user WHERE id IN foreach collectionlist itemid open( separator, close) #{id} /foreach /select传入ListInteger ids Arrays.asList(1, 2, 3);生成 SQLSELECT * FROM user WHERE id IN (1, 2, 3)(2). 批量插入insert idinsertUsers parameterTypelist INSERT INTO user (username, age) VALUES foreach collectionlist itemu separator, (#{u.username}, #{u.age}) /foreach /insert【注意】此时属性openclose都没有写传入ListUser users List.of( new User(Tom, 20), new User(Jerry, 22) );生成 SQLINSERT INTO user (username, age) VALUES (Tom, 20), (Jerry, 22)(3). 遍历 Map实现动态 UPDATE 字段foreach collectionmap itemval indexkey ${key} #{val} /foreach示例int updateForEach(Param(updateFields) MapString, Object updateFields, Param(id) Long id);【注意】此时的key用的是${key}因为是数据库字段不能用#{key}否则拼接的数据库字段会加上字符串4、常见坑点提示问题说明collectionlist如果参数是List要写list不是写变量名foreach必须配合open/close/separator否则 SQL 拼接可能出错item#{}中的item要和声明保持一致否则无法解析参数避免用${}插值容易引发 SQL 注入问题2-7、include标签MyBatis 中的include标签用于在 XML 映射文件中复用 SQL 片段类似 Java 中的方法提取可以提高 SQL 语句的复用性和可维护性。1、使用场景多个 SQL 中有相同字段、相同条件、重复的列名等希望统一维护公共 SQL 内容避免拷贝粘贴2、基本语法1. 定义可复用的 SQL 片段使用sql标签sql idbaseColumnList id, name, age, gender, email /sql2. 引用 SQL 片段使用include标签select idselectAll resultTypeUser SELECT include refidbaseColumnList / FROM users /select3、完整示例!-- 定义通用字段列表 -- sql idbaseColumnList id, name, age, gender, email /sql !-- 使用 include 引用 -- select idselectById resultTypeUser SELECT include refidbaseColumnList / FROM users WHERE id #{id} /select4、refid 范围说明sql id...的id必须在当前命名空间中唯一如果跨命名空间使用需要使用namespace.id引用例如include refidcom.example.mapper.UserMapper.baseColumnList /⚠️ 注意事项不支持sql中再嵌套sql或include