MyBatis
动态SQL
1.什么是动态SQL?
-
概述:根据不同的参数,执行不同的SQL语句;当我么们使用了 JDBC后,就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦;通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解,MyBatis 的强大特性之一便是它的动态 SQL! -
测试动态SQL:
在操作之前我们需要准备一个blog
表:
CREATE TABLE `blog` (
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
) ENGINE=INNODB DEFAULT CHARSET=utf8
插入一些数据:
在配置中开启自动驼峰命名规则和日志:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2.if
<if> </if>
提供了一个可选的文本查找类型的功能,通过author和title查找:如果传入的author为null,就用title查找;
方法接口:
public interface BlogMapper {
List<Blog> getBlogByIf(Map map);
}
Mapper.xml文件:
<select id="getBlogByIf" resultType="Blog" parameterType="map">
select * from mybatis.blog where
<if test="title!=null">
title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</select>
测试类:
public void testGetBlogByIf(){
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("title","Java");
//map.put("author","Mr.zhang");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
日志查询结果:
当我们只操作map.put("title","Java");
时,日志的sql语句为:
当我们同时操作map.put("title","Java"); map.put("author","Mr.zhang");
3.choose
<choose> </choose>
有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。when相当于case,otherwise相当于default:
<select id="queryBlogByChoose" resultType="Blog" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test="title!=null">
title=#{title}
</when>
<when test="author!=null">
and author=#{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
public void testChoose(){
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("author","Mr.chen");
mapper.queryBlogByChoose(map);
}
测试类中什么都不操作时,程序不报错,日志中的sql语句为:
测试类中操作了map.put("author","Mr.chen");
时:
4.where
<where> </where>
在一个以上的 if 条件有值的情况下才去插入"WHERE"子句,而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
<select id="getBlogByIf" resultType="Blog" parameterType="map">
select * from mybatis.blog where
<if test="title!=null">
title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</select>
日志查询结果:
当我们什么都没操作时,where
就被滞空了,程序运行报错:
我们使用<where></where>
后,程序正常运行,结果为:
当我们只操作map.put("title","Java");
时,会自动去除and:
5.set
<set> </set>
set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">
title=#{title},
</if>
<if test="author!=null">
author=#{author}
</if>
</set>
where id=#{id}
</update>
public void testSet(){
SqlSession session = MyBatisUtils.getSession(true);
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","dc71eb50a4334000807a2fe87c9db433");
map.put("author","Mr.zhang");
mapper.updateBlog(map);
}
日志查询结果:去除逗号
set 等价的自定义 trim 元素:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
6.foreach
<foreach> </foreach>
允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
<select id="queryBlogByForeach" resultType="Blog" parameterType="map">
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
public void testForeach(){
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String,List> map = new HashMap();
List<String> ids = new ArrayList<String>();
ids.add("dc71eb50a4334000807a2fe87c9db433");
ids.add("293b14a5e5f541489d91efdd911d169c");
ids.add("4bbb8d6b9ac94d7ca77f8ec6d33ef11b");
map.put("ids",ids);
mapper.queryBlogByForeach(map);
}
查询结果:
- 注意:可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以"list"作为键,而数组实例的键将是"array"。
//下篇再见…谢谢