相关文章推荐
火星上的蚂蚁  ·  jar包在linux下不产生报错日志也无法启 ...·  2 月前    · 
想出家的电梯  ·  如何将毫秒转换为天/小时/分钟_SQL将毫秒 ...·  7 月前    · 
性感的野马  ·  C++基础——非类型模板参数_c++非类型实 ...·  8 月前    · 
严肃的柚子  ·  四、WPF 切换按钮背景图样式写法 - ...·  1 年前    · 
俊秀的路灯  ·  Python解决表格可视化_python绘制 ...·  1 年前    · 
Code  ›  Mybatis【13】-- Mybatis动态sql标签怎么使用?开发者社区
select mybatis sql注入 mybatis动态sql
https://cloud.tencent.com/developer/article/1943349
冷冷的茄子
1 年前
作者头像
秦怀杂货店
0 篇文章

Mybatis【13】-- Mybatis动态sql标签怎么使用?

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 技术杂货店 > 正文

Mybatis【13】-- Mybatis动态sql标签怎么使用?

发布 于 2022-02-15 14:28:39
2.7K 0
举报

mybatis 有一个强大的特性,其他框架在拼接 sql 的时候要特别谨慎,比如哪里需要空格,还要注意去掉列表最后一个列名的逗号, mybtis 的动态 sql 可以帮助我们逃离这样的痛苦挣扎,那就是 动态SQL .

它还可以处理一种情况,当你不确定你的参数,不知道是不是为空的时候,我们不需要在业务逻辑中判断,直接在 sql 中处理,代码无比简洁。主要的动态 sql 标签如下:

  • <if></if>
  • <where></where>(trim,set)
  • <choose></choose>(when, otherwise)
  • <foreach></foreach>

注意事项:在 mapper 中如果出现大于号( > ),小于号( < ),大于等于号( >= ),小于等于号( <= )等,最好需要转换成为实体符号,这是因为 mapper 是 XML 文件, xml 文件本身就含有较多的 <> 这样的尖括号,所以解析的时候可能会解析出错。

原符号

<

<=

>

>=

&

'

"

替换符号

&lt;

&lt;=

&gt;

&gt;=

&amp;

&apos;

&quot;

<if></if>标签

我们经常需要根据where后面的条件筛选出需要的数据,当多个条件拼接的时候,我们一般使用 <if></if> ,如果 if 里面的条件成立,那么就会使用标签的语句,但是我们可以知道 where 句子第一个标签是没有 and 的,而后面的条件都需要 and 。

所以有一种做法是第一个使用 where 1 = 1 ,这个条件恒成立,后面的所有子语句都加上 and ,如果增加判断,那么我们只需要加 <if> 标签就可以了。

    <!-- 动态sql if标签-->
    <!-- &可以使用and来代替 ,注意!=需要连在一起写-->
    <select id="selectStudentByDynamicSQL" resultType="Student">
        <!--最常用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能写value,了解即可,容易sql注入,执行效率低,不建议使用-->
        select id,name,age,score
        from student
        where 1=1
        <if test="name != null and name != ''">
            and name like '%' #{name} '%'
        <if test="age > 0">
            and age > #{age}
    </select>

当有两个查询条件的时候, sql 语句是:

select * from student where 1=1 and name like '%' ? '%' and age > ? 

当有一个查询条件的时候: sql 语句就变成:

select * from student where 1=1 and name like '%' ? '%'

当没有查询条件的时候, sql 语句是:

select * from student where 1=1

<if></if> 标签需要手动在 where 后面添加 1=1 语句,这是因为如果 <if> 后面的条件都是 false 的时候, where 后面如果没有 1=1 语句, sql 就剩下一个空空的 where , sql 就会报错。所以在where后面需要加上永真句子 1=1 ,但是这样有一个问题,当数据量比较大的时候,会严重影响sql的查询效率。

<where></where>,<trim></trim>,<set></set> 标签

使用 <where></where> 标签,在有查询语句的时候,自动补上 where 子句,在没有查询条件的时候,不会加上 where 子句,这也就解决了我们上面所涉及到的问题。

剩下的就是 <if> 标签的 and 子句,第一个 <if> 片段里面可以不包含 and ,也可以包含,系统会自动去掉 and ,但是其他的 <if> 片段里面的 and ,必须写上,否则会出错。下面的写法中,如果 name 为 null ,第二个 if 标签中的 and 也会被去掉,不会报错。

    <select id="selectStudentByDynamicSQLWhere" resultType="Student">
        <!--最常用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能写value,了解即可,容易sql注入,执行效率低,不建议使用-->
        select id,name,age,score
        from student
        <where>
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            <if test="age > 0">
                and age > #{age}
        </where>
    </select>

如果 where 里面条件是不规范的,那我们可以通过 <trim></trim> 来自定义where元素的功能, <trim> 标签主要有以下属性:

  • prefix :在包含的内容前加上前缀,不是百分之百会加,会根据需要自动加
  • suffix :在包含的内容后面加上后缀,不是百分之百会加,会根据需要自动加
  • prefixOverrides :可以把包含内容的首部某些内容忽略(不能自己增加),不一定会忽略,根据需要自动忽略
  • suffixOverrides :也可以把包含内容的尾部的某些内容忽略(不能自己增加),同上

下面这样的是 错误的 ,当传入的 name 不为空,而且 age 大于0的时候,会根据需要加上 where ,但是根据前缀进行忽略的时候会报错,因为本来就没有 and ,何来忽略一说。

    <select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                name like '%' #{name} '%'
            <if test="age > 0">
                age > #{age}
        </trim>
    </select>

不会自己增加 and 在第二个 <if> 里面的 age 前面:

下面的是 正确的 ,我们在两个 <if> 标签前面都增加了 and ,第二个 and 会自动去掉:

    <select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            <if test="age > 0">
                and age > #{age}
        </trim>
    </select>

下面是后缀模式, prefix="set" 表示在整个语句前面加上前缀 set , suffixoverride="," 表示每一个语句后面的后缀" , "可以被忽略, 如果是需要的话 。 suffix=" where id = #{id} 表示在整个语句后面增加 where id = #{id}, :

update user
<trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
  <if test="name != null and name.length()>0"> name=#{name} , </if>
  <if test="age != null "> age=#{age} ,  </if>
</trim>

当然,我们对上面的语句还有动态解决的方案,那就是 <set> 标签:

    <update id="updateStudent">
  update student
            <!-- 第一个if标签的逗号一定要有,最后一个标签的逗号可以没有-->
            <if test="name != null"> name=#{name},</if>
            <if test="age != null">age=#{age},</if>
            <if test="score != null"> score=#{score},</if>
         where id=#{id}
 </update>

<choose>, <when>, <otherwise> 标签

有时候,我们只想去匹配第一个条件,或者第一个条件不匹配的时候才会去匹配第二个条件,不像 <where></where> 标签里面的 <if></if> 一样会去判断所有的子语句是否可以匹配,而是遇到一个匹配的就会执行跳出 <choose></choose>

    <!--  selectStudentByDynamicSQLChoose 类似于switch,满足后就不会判断后面的了-->
    <!-- 如果名字不为空,那么按照名字来查询,如果名字为空,就按照年龄来查询,如果没有查询条件,就没有查询条件 -->
    <select id="selectStudentByDynamicSQLChoose" resultType="Student">
        <!--最常用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        select id,name,age,score
        from student
        <where>
            <choose>
                <when test="name != null and name != ''">
                    and name like '%' #{name} '%'
                </when>
                <when test="age > 0">
                    and age > #{age}
                </when>
                <otherwise>
                    and 1 != 1
                </otherwise>
            </choose>
        </where>
    </select>

<choose> 标签就像是 switch 语句,每一个 <when> 都像是 case , 后面默认跟上break语句 ,只要满足一个就不会判断后面的子语句了,当前面所有的 <when></when> 都不执行的时候,就会执行 <otherwise></otherwise> 标签的内容,这个内容也就像是 switch 语句里面的 default 。

foreach标签

动态SQL要有一个比较多的操作是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。需要注意的点:

  • collection 表示需要遍历的集合类型, array 表示需要遍历的数组
  • open , close , separator 是对遍历内容的SQL拼接
  • foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项( item )和索引( index )变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。
  • 你可以将任何可迭代对象(如 List 、 Set 等)、 Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时, index 是当前迭代的次数, item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时, index 是键, item 是值。

遍历数组

1.比如我们需要查找学生的 id 为1,2,3的学生信息,我们不希望分开一次査一个,而是希望将数组id一次传进去,查出来一个学生的集合。

sql接口可以这样写,传入一个对象的数组:

public List<Student>selectStudentByDynamicSQLForeachArray(Object[]studentIds);

sql语句如下,遍历array数组的时候,指定左边符号是左括号,右边是右括号,元素以逗号分隔开:

    <!-- select * from student where id in (1,3) -->
    <select id="selectStudentByDynamicSQLForeachArray" resultType="Student">
        select id,name,age,score
        from student
        <if test="array !=null and array.length > 0 ">
            where id in
            <foreach collection="array" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
    </select>

遍历基础数据类型的list

2.当遍历的是一个类型为 int 的 list 列表时:

public List<Student>selectStudentByDynamicSQLForeachList(List<Integer>studentIds);

sql 语句如下, colleaction 指定为 list :

    <select id="selectStudentByDynamicSQLForeachList" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
    </select>

遍历对象的list

3.当遍历的是一个类型为对象的 list :

public List<Student>selectStudentByDynamicSQLForeachListStudent(List<Student>students);

sql 语句里面与上面相似,只是在使用属性的时候不太一样:

<select id="selectStudentByDynamicSQLForeachListStudent" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
                #{stu.id}
            </foreach>
    </select>

<sql></sql> 标签

用于定义 sql 片段,方便在其他 SQL 标签里面复用,在其他地方复用的时候需要使用 <include></include> 子标签, <sql> 可以定义 sql 的任何部分,所以 <include> 标签可以放在动态SQL的任何位置。

    <sql id="selectHead">
  select id,name,age,score
   from student
    <!-- 可读性比较差 -->
    <select id="selectStudentByDynamicSQLfragment" resultType="Student">
        <include refid="selectHead"></include>
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
 
推荐文章
火星上的蚂蚁  ·  jar包在linux下不产生报错日志也无法启动的悬案_linux中运行jar包没有进程产生,日志正常-CSDN博客
2 月前
想出家的电梯  ·  如何将毫秒转换为天/小时/分钟_SQL将毫秒转换为天、小时、分钟_将小时、分钟转换为天、小时、分钟 - 腾讯云开发者社区 - 腾讯云
7 月前
性感的野马  ·  C++基础——非类型模板参数_c++非类型实体-CSDN博客
8 月前
严肃的柚子  ·  四、WPF 切换按钮背景图样式写法 - 清风神剑 - 博客园
1 年前
俊秀的路灯  ·  Python解决表格可视化_python绘制表格图片-CSDN博客
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号