Bootstrap

MyBatis第七篇:动态sql

回想一下我们在没有学习MyBatis之前是在进行多参数模糊查询时是怎么做的?我们要判断很多条件,然后看是否符合条件然后在进行附加sql语句。代码写起来非常的繁琐,并且还极易出错。下边看一下MyBatis是怎样做的吧。其实底层的原理是一样的。


前言

动态sql主要是使用各种标签进行实现的。


一、<if> 标签

if 标签主要用来判断条件是否成立,如果成立则添加标签中的内容,反之则不添加

它与java中的if判断十分的相似,和jsp中的核心标签库中的<c:if>也十分的相似

//注意这是类似,并不是一模一样
if( test="判断条件"){
//若为true就执行
}

用法实例:
如果test条件成立就拼接if标签中的sql片段

<select id="getEmployees" parameterType="Employee" resultMap="baseResultMap">
   select * from employee where 1=1
   <!--传递进来的是一个对象,此时可以直接使用对象的属性-->
      <if test="name!=null and name!=''">
            and e_name=#{name}
      </if>
      <if test="age!=null">
            and e_age>#{age}
      </if>
</select>

二、<where> 标签

where 标签主要用来在sql中添加where关键字,当where标签体中有条件成立时会自动附加where标签,如果没有条件成立则不会附加where标签。where标签会自动忽略离它最近的and|or关键字,并不需要在写1=1
代码如下(示例):

用法实例:

<select id="getEmployees" parameterType="Employee" resultMap="baseResultMap">
        select * from employee
   <where>
           <if test="name!=null and name!=''">
                   and e_name=#{name}
           </if>
           <if test="age!=null">
                   and e_age>#{age}
           </if>
     </where>
</select>

我们看一下生成的sql语句

1.当不传入name和age时的sql为:

select * form employee 

2.只传递name(忽略了前边的and)

select * from employee where  e_name=#{name}

3.传递name和age(忽略了前边的and)

select * from employee where  e_name=#{name}  and e_age>#{age}

三、choose, when, otherwise 标签

choose,when,otherwise 用于条件判断,当有条件成立时附加该 sql 语句,后续条件都得不到执行。如果所有条件都不成立则执行 otherwise 中的 sql 语句.
这个标签非常像java中的if… else if…else
示例:

<select id="getEmployees" parameterType="Employee" resultMap="baseResultMap">
     select * from employee
    <where>
       <choose>
          <when test="name!=null">
             and e_name=#{name}
         </when>
         <when test="age!=null">
            and e_age=#{age}
        </when>
             <otherwise>
                    1=1
             </otherwise>
       </choose>
     </where>
</select>

需要注意的是如果when条件有成立的话,这个choose标签就会添加成立对应的sql语句,并结束。后续的when条件将不再判断。如果所有的条件都不成立就会添加otherwise标签中的sql语句。

简单看一下生成的sql语句

1.当不传入name和age时的sql为:

select * form employee  where 1 =1

1.当传入name和age时的sql为:

select * form employee  where e_name=#{name}

因为name在age的上边,所以name添加后age将不再添加

四、<set> 标签

set标签用于更新,如果 set 标签中有条件成立时就会附加 set 关键字,只更新满足条件的字段,更新效率会有提升。Set 标签会自动忽略掉最后一个跟 sql 语句无关的逗号。

实例:根据员工id更新员工信息

<update id="updateEmployee" parameterType="Employee">
     update employee
    <set>
       <if test="name!=null">
           e_name=#{name},
       </if>
       <if test="gender!=null">
          e_gender=#{gender},
       </if>
       <if test="age!=null">
          e_age=#{age},
       </if>
    </set>
     where e_id=#{id}
</update>

五、<Trim> 标签

Trim标签该标签功能十分的强大,它可以包含其他动态sql标签比如:where 、set 、update

Trim 可以附加 sql 中任意关键字,当 trim 中有条件成立时就附加指定的关键字。

Prefix 指定前缀关键字,可以附加 where set …
Suffix 指定后缀关键字
PrefixOverrides 忽略掉指定的与 sql 无关的前缀关键字
suffixOverrides 忽略掉指定的与 sql 无关的后缀关键字

示例:应用前缀where

<select id="getEmployees" parameterType="Employee" resultMap="baseResultMap">
    select * from employee
    <trim prefix="where" prefixOverrides="and|or">
        <if test="name!=null and name!=''">
             and e_name=#{name}
        </if>
        <if test="age!=null">
            and e_age>#{age}
        </if>
    </trim>
</select>
如果trim中有条件成立,则使用前缀关键字where,并忽略and|or

应用于set

<update id="updateEmployee" parameterType="Employee">
update employee
   <trim prefix="set" suffixOverrides=",">
        <if test="name!=null">
			e_name=#{name},
		</if>
		<if test="gender!=null">
			e_gender=#{gender},
		</if>
		<if test="age!=null">
			e_age=#{age}
		</if>
   </trim>
			where e_id=#{id}
</update>

六、<foreach> 标签

foreach标签主要用来遍历,可以是list Map 数组

语法:

<foreach collection="遍历的集合" item="集合中当前元素" index="下标" open="" separator="每次遍历的分隔符" close="">
动态sql部分
</foreach>

collection 表示集合的类型
Item: 表示集合中的每个数据元素
Separator: 每次循环完毕后都要附加指定的分隔符。
Open: 在循环之前要附加的关键字。
Close:循环结束之后要附加的关键字
Index: 循环集合的索引值

举例:批量添加:

<insert id="addBatchEmployees">
     insert into employee (e_name,e_gender,e_age) values
    <foreach collection="list" item="emp" separator=",">
          (#{emp.name},#{emp.gender},#{emp.age})
   </foreach>
</insert>

批量删除:

<delete id="deleteEmployees">
    delete from employee where e_id in
   <foreach collection="list" item="id" separator="," open="(" close=")">
          #{id}
    </foreach>
</delete>

批量更新:

<update id="updateEmployees">
   <foreach collection="list" item="emp" separator=";">
        update employee
   <set>
      <if test="emp.name!=null">
          e_name=#{emp.name},
     </if>
     <if test="emp.gender!=null">
         e_gender=#{emp.gender},
     </if>
     <if test="emp.age!=null">
         e_age=#{emp.age}
     </if>
     </set>
    where e_id=#{emp.id}
    </foreach>
</update>

批量更新其实就是生成了多条sql语句
注意: mysql 不支持批量更新,如果允许批量更新的话请在 jdbc 链接的后面附加参数
jdbc:mysql:///test2?allowMultiQueries=true


七、<bind> 标签

bind标签多用在模糊查询

语法:

 <bind name="pattern" value="'%' + _parameter.getName() + '%'" />
 放在查询sql语句上边

name:表示查询表示
value:表示查询的结果"’%’ + _parameter +’%’"固定写法。getXXX根据什么查就写什么

示例:

<select id="getEmployeeByLinkeName" resultMap="baseResultMap">
   <bind name="pattern" value="'%' + _parameter.getName() + '%'" />
      select * from employee where e_name like #{pattern}
</select>

模糊查询使用sql函数

使用concat()函数可以解决sql注入攻击的问题,并且比较简单。

<select id="getStudentsByName" resultType="Student" parameterType="String">
        select * from student where name like concat('%',#{name},'%')
    </select>
;