MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
动态sql的标签
元素 | 作用 | 描述 |
if | 条件判断 | 多条件判断 |
choose(when、otherwise) | 条件选择,相当于Java中的when | 多条件分支判断 |
where、set | 辅助(条件) | 处理SQL语句拼接问题 |
foreach | 循环(批量插入 修改) | 循环(批量使用) |
if标签-单条件判断
作用:筛选条件语句
<!--如果姓名不为空则按姓名查找 如果姓名为空则按邮箱查找 否则查询全部-->
<select id="selectConditon" resultType="com.kuangziyao.mapper.User">
select * from tb_user
<where>
<if test="name != null and name !=''">
and name = #{name}
</if>
<if test="email != null and email!=''">
and email = #{email}
</if>
</where>
</select>
choose,when, otherwise标签 多条件分支判断
有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
chooes–when–otherwise语句,只会选择其中的一个执行,如果存在otherwise语句,且when中的语句都不通过,那么就执行otherwise,如果不存在otherwise语句,且when语句都不成立,就不进行拼接sql,也就是不执行chooes里面的语句。
// mapper层方法
//当三者不为空的时候 按状态 公司名 品牌名查询 三个条件都会执行一遍
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName")
String companyName, @Param("brandName") String brandName);
// xml
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose>
<when test="status != null">
and status = #{status}
</when>
<when test="companyName != null and companyName !=''">
and company_name like #{companyName}
</when>
<otherwise>
and brand_name like #{brandName};
</otherwise>
</choose>
</where>
</select>
set标签
这个标签配合if标签一起用 一般用于修改语句 如果传递的参数为null 那么就不会修改该列的值
//这里注意 test="参数" 这里的参数 是前端传过来的值就是你前端页面上是什么 这里就要写什么
//而下面的name=#{name} 第一个name是你数据库中的字段 #{name}中是你的前端传过来的值
<update id="updateUser" parameterType="User">
update tb_user
<set>
<if test="name != null and name != ''">
name=#{name},
</if>
<if test = "pwd != null">
pwd = #{pwd},
</if>
<if test = "email != null">
email = #{email},
</if>
</set>
where id = #{id}
</update>
foreach标签
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
查询id为1 3 5 的用户信息
正常sql语句为 select * from tbl_user02 where id in(1,3,5);
下面的为使用foreach遍历 循环查询
解释:
<foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分割符">
#{item的值}
</foreach>
标签属性:
collection:表示循环的对象是数组还是list集合。如果dao方法的形参是数组,collection="array";
如果dao方法形参是list,collection="list";
open:循环开始的字符。sql.append("(");
close:循环结束的字符。sql.append(")");
item:集合成员,自定义的变量。Integer item = idList.get(i);
separator:集合成员之间的分隔符。sql.append(",");
#{item的值}:获取集合成员的值;
具体代码实现
// dao层
//传递的参数为id数组所以mapper层的collection="list"
public List<User> findByIds(Integer[] ids);
// mapper层
<select id="findByIds" resultType="com.wx.entity.User">
select * from tbl_user02 where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
// 测试类
@Test
public void testFindByIds() throws Exception{
Reader rd = Resources.getResourceAsReader("conf.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(rd);
SqlSession session = factory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
Integer[] ids = {1,3,5};
List<User> user = userDao.findByIds(ids);
System.out.println(user);
session.close();
}
SQL片段
可以用于提取可以公用的sql片段,提高代码复用率。
1、使用SQL标签提取公共部分
<sql id="if-title-author">
<if test="title!=null">
title like "%"#{title}"%"
</if>
<if test="author!=null">
and author like "%"#{author}"%"
</if>
</sql>
// 2.在需要使用的地方使用标签include引用即可
<select id="queryBolgIf" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author"/>
</where>
</select>
注意事项:
1、提取的公共SQL语句不要太复杂,这样会降低代码的复用率,共用的sql语句尽量简单。 2、提取的SQL语句中,最好不要包含where/set标签,这样也会降低代码复用率,而且可能会出问题。
所谓的动态SQL,本质上还是SQL,只不过在SQL层面的代码中执行一些逻辑代码,对SQL语句进行一些动态的控制