动态SQL的标签使用和入门写法

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

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

if

select * from user where 1=1 
<if test="id != null and id != ''">
    and id = #{id}
</if>
<if test="name != null and name != ''">
    and name = #{name}
</if>

为什么使用1=1作为参数都很清楚了,如果没有1=1且条件if为true,那么拼接的sql语句会变成,是错误的拼接

如果没有匹配又没有1=1的条件会怎么样?

select * from user where

如果匹配的只是第二个条件又会怎样?

select * from user where and name = nameValue

if的多条件使用,即使没有1=1也不会出现问题,因为此时有一个固定条件,只要确保不出现 where 和 and的连接的情况即可。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

choose、when、otherwise

<select id="testStudayChoose" resultType="User">
   select * from `user`
    <where>
        <choose>
            <when test="name != null and name != ''">
                and name = #{name}
            </when>
            <when test="password != null and password != ''">
                and password = #{password}
            </when>
            <otherwise>
                and uid = 1
            </otherwise>
        </choose>
    </where>
</select>

下面会讲到<where>,其实就是代替了where 1=1。

值得注意的是choose标签相当于switch,满足第一个条件以后就不会执行其他语句拼接,例如name和password两个参数都传也只会执行name。

而otherwise标签则是相当于default当条件都不满足时执行的拼接sql。

trim、where、set

<where> </where>

前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 where 1=1 设置成动态条件

<select id="findOneSql" resultType="User">
    select * from `user`
    <where>
        <if test="id != null and id != ''">
            and uid = #{uid}
        </if>
        <if test="birthday != null">
            and birthday = #{birthday}
        </if>
    </where>
</select>

where标签在if条件都不满足时取消的where的条件拼接,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

trim标签也可以完成相同的功能

<select id="findOneSql" resultType="User">
    select * from `user`
    <trim prefix="WHERE" prefixOverrides="AND |OR"> 
        <if test="id != null and id != ''">
            and uid = #{uid}
        </if>
        <if test="birthday != null">
            and birthday = #{birthday}
        </if>
    </trim>
</select>

值得注意的是trim标签中的每个属性

属性描述
prefix 给sql语句拼接的前缀
suffix 给sql语句拼接的后缀
prefixOverrides 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
suffixOverrides 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定

<set></set>

<update id="updateOneSql">
    update `user`
    <set>
        <if test="name != null and name != ''">
            `name` = #{name},
        </if>
        <if test="birthday != null">
            birthday = #{birthday}
        </if>
    </set>
    where uid = #{uid}
</update>
<-- 或使用的写法 -->
<
trim prefix="SET" suffixOverrides=","> ... </trim>

foreach 

例如使用场景为 uid in () 括号中位多个条件

<select id="setValueListSql" parameterType="java.util.List" resultType="User">
    SELECT * from `user` where uid in
    <foreach collection="list" open="(" separator="," close=")" item="item" index="index">
        #{item}
    </foreach>
</select>
    • collection:表示传入过来的参数的数据类型。该参数为必选。要做 foreach 的对象,作为入参时,List 对象默认用 list 代替作为键,数组对象有 array 代替作为键,Map 对象没有默认的键。当然在作为入参时可以使用 @Param(“keyName”) 来设置键,设置 keyName 后,list,array 将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:
      如果 User 有属性 List ids。入参是 User 对象,那么这个 collection = “ids” 如果 User 有属性 Ids ids;其中 Ids 是个对象,Ids 有个属性 List id;入参是 User 对象,那么 collection = “ids.id”
      • 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list
      • 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array
      • 如果传入的参数是多个的时候,我们就需要把它们封装成一个 Map 了,当然单参数也可以封装成 map。
    • item: 循环体中的具体对象。支持属性的点路径访问,如 item.age,item.info.details。具体说明:在 list 和数组中是其中的对象,在 map 中是 value,该参数为必选。(它是每一个元素进行迭代时的别名)
    • index:在 list 和数组中,index 是元素的序号;在 map 中,index 是元素的 key。
    • open:表示该语句以什么开始
    • close:表示该语句以什么结束
    • separator:表示在每次进行迭代之间以什么符号作为分隔符

补充

 在insert时使用foreach批量插入

insert into user(id,name)
values
<foreach collection="list" separator=","  item="item" index="index">
        (#{item.id},#{item.name})
</foreach>

 

posted @ 2020-08-14 17:54  一半人生  阅读(768)  评论(0编辑  收藏  举报