Mybatis动态SQL
User表结构如下:
一、动态SQL:if标签、where标签
需求:使用username和gender来查询数据,如果username为空,则只根据gender来查询数据;如果gender为空,则只根据username来查询数据
如果我们不使用动态SQL来书写SQL语句
1 2 3 | <select id= "queryUserByUsernameAndGender" resultType= "com.mybatis.entity.User" > SELECT * FROM user WHERE username=#{username} AND gender=#{gender} </select> |
1、如果username为空,那么SQL语句就会变成这样,这个样子自然是查询不到数据的
1 | SELECT * FROM user WHERE username= 'null' AND gender= 'female' ; |
2、如果gender为空,那么SQL语句就会变成这样,这个样子也是查询不到数据的
1 | SELECT * FROM user WHERE username= 'xiaomao' AND gender= 'null' ; |
那么怎么解决上述的问题呢?这个时候就需要使用if标签,加上了if标签的SQL语句如下
1 2 3 4 5 6 7 8 9 10 11 | <select id= "queryUserByUsernameAndGender" resultType= "com.mybatis.entity.User" > SELECT * FROM user WHERE // 如果条件成立则执行if内的SQL语句 < if test= "username != null" > username=#{username} </ if > < if test= "gender != null" > AND gender=#{gender} </ if > </select> |
3、这个时候如果gender为空的情况下,SQL语句就变成了这样,看样子已经符合我们的需求了
1 | SELECT * FROM user WHERE username= '小毛' ; |
4、但是,如果gender为空的时候,SQL如下,这个语句明显是错误的,因为多了一个AND关键字
1 | SELECT * FROM user WHERE AND gender= 'female' ; |
5、那么如何处理这个多出来的AND关键字呢?这个时候我们就需要配合使用另外一个标签,where标签
1 2 3 4 5 6 7 8 9 10 11 12 | <select id= "queryUserByUsernameAndGender" resultType= "com.mybatis.entity.User" > SELECT * FROM user <where> < if test= "username != null" > username=#{username} </ if > < if test= "gender != null" > AND gender=#{gender} </ if > </where> </select> |
6、到现在为止我们就可以满足需求了,即
username和gender都存在的情况下:以两个条件查询
username存在,gender不存在的情况下,以username作为条件查询
username不存在,gender存在的情况下,以gender作为条件查询
<if>标签:满足该标签的条件之后才能去拼接标签内的SQL
<where>标签:如果where标签的返回结果是以 AND 或者 OR 开头,那么它会帮我们剔除多余的AND 和 OR
二、动态SQL:set标签
需求:根据id更新用户的username和gender信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <update id= "updateUserById" > UPDATE user set < if test= "username != null" > username=#{username}, </ if > < if test= "gender != null" > gender=#{gender} </ if > <where> < if test= "id != null" > id = #{id} </ if > </where> </update> |
1、如果username为空,那么SQL将会变成如下的样子,这样子的SQL没有任何问题
1 | UPDATE user set gender=? WHERE id = ? |
2、如果gender为空的话,那么SQL就会变成如下的样子,很明显这个SQL是有问题的,因为它在username=?后面多了一个逗号
1 | UPDATE user set username=?, WHERE id = ? |
3、要解决上面的问题,我们需要使用<set>标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <update id= "updateUserById" > UPDATE user <set> < if test= "username != null" > username=#{username}, </ if > < if test= "gender != null" > gender=#{gender} </ if > </set> <where> < if test= "id != null" > id = #{id} </ if > </where> </update> |
<set>标签:如果set标签内的SQL返回值以逗号结尾,那么set标签会剔除多余的逗号.
三、动态SQL:choose(when,otherwise)语句
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <select id= "queryUserByOneCondition" resultType= "com.mybatis.entity.User" > SELECT * FROM user <where> <choose> <when test= "id != null" > id = #{id} </when> <when test= "username != null" > username = #{username} </when> <otherwise> address=#{address} </otherwise> </choose> </where> </select> |
1、如果id满足<when>标签的条件,那么SQL语句如下
1 | SELECT * FROM user where id=? |
2、如果id不满足<when>标签的条件,username满足<when>标签的条件,那么SQL语句如下
1 | SELECT * FROM user where username=? |
3、如果id和username都不满足<when>标签的条件,那么SQL语句如下
1 | SELECT * FROM user where address=? |
四、动态SQL:SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时通过id直接调用.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 抽取SQL片段,这里有一个id,在别的SQL语句中可以通过这个id引入SQL片段 <sql id= "selectBasic" > SELECT * FROM user </sql> <select id= "queryUserByOneCondition" resultType= "com.mybatis.entity.User" > // 引入SQL片段,相当于是 SELECT * FROM user <include refid= "selectBasic" ></include> <where> <choose> <when test= "id != null" > id = #{id} </when> <when test= "username != null" > username = #{username} </when> <otherwise> address=#{address} </otherwise> </choose> </where> </select> |
五、动态SQL:trim标签
trim标记是一个格式化的标记,可以完成set或者是where标记的功能
1、替换where的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <select id= "queryUserByUsernameAndGender" resultType= "com.mybatis.entity.User" > SELECT * FROM user <where> < if test= "username != null" > username=#{username} </ if > < if test= "gender != null" > AND gender=#{gender} </ if > </where> </select> <select id= "queryUserByUsernameAndGender" resultType= "com.mybatis.entity.User" > SELECT * FROM user // prefix:为trim返回的结果前面添加一个where // prefixOverrides:剔除trim返回的结果后面的 and 或者是 or <trim prefix= "where" prefixOverrides= "and | or" > < if test= "username != null" > username=#{username} </ if > < if test= "gender != null" > AND gender=#{gender} </ if > </trim> </select> |
prefix:为整个的sql语句添加一个前缀
prefixoverride:去掉第一个and或者是or
2、替换set功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <update id= "updateUserById" > UPDATE user <set> < if test= "username != null" > username=#{username}, </ if > < if test= "gender != null" > gender=#{gender} </ if > </set> <where> < if test= "id != null" > id = #{id} </ if > </where> </update> <update id= "updateUserById" > UPDATE user <trim prefix= "set" suffixOverrides= "," > < if test= "username != null" > username=#{username}, </ if > < if test= "gender != null" > gender=#{gender} </ if > </trim> <trim prefix= "where" > < if test= "id != null" > id = #{id} </ if > </trim> </update> |
suffix:后缀
suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)
六、动态SQL:foreach语句
1、UserMapper接口
1 2 3 4 5 | // 批量添加,使用@Param注解之后在collection中只要写注解对应的value值就可以了,不需要再去判断是数组,List,Map之类的了. public abstract Boolean addBatch( @Param ( "Users" ) List<User> list); // 批量删除 public abstract Boolean deleteBatch( @Param ( "ids" )Integer[] integers); |
2、UserMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 批量添加 <insert id= "addBatch" > INSERT INTO user VALUES <foreach collection= "Users" item= "user" separator= "," > ( null ,#{user.username},#{user.gender}, null , null ) </foreach> </insert> // 批量删除 <delete id= "deleteBatch" > DELETE FROM user WHERE id IN <foreach collection= "ids" item= "id" open= "(" close= ")" separator= "," > #{id} </foreach> </delete> |
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:在foreach返回的结果前面拼接的字符串
close:在foreach返回的结果后面拼接的字符串
separator:遍历对象之间的分隔符
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?