01 动态SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。
动态SQL就是指根据不同查询条件,生成不同的SQL语句
MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
if:提供一种可选的查找文本功能。
官方文档示例:
<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:有点像 Java 中的 switch 语句。
官方文档示例:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim, where, set:解决前几个例子中where条件不匹配的情况下,SQL语句报错的问题
where
元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where
元素也会将它们去除。
官方文档示例:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
set
元素可以用于动态包含需要更新的列,而舍去其它的。
官方文档示例:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
foreach允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
官方文档示例:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
测试:模糊查询
UserMapper接口
//模糊查询
public abstract List<User> getUsers(Map map);
userMapper.xml文件
<select id="getUsers" parameterType="Map" resultType="user" >
select * from user
<where>
<if test="name != null">
name like concat("%",#{name},"%")
</if>
<if test="id!=null">
and id = #{id}
</if>
</where>
</select>
Juint测试代码1
@Test
public void getUsers(){
SqlSession session = MybatisUtil.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map map = new HashMap();
List<User> users = mapper.getUsers(map);
for (User user : users) {
System.out.println(user);
}
}
测试结果1:
Juint测试代码2
@Test
public void getUsers(){
SqlSession session = MybatisUtil.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("name","H");
List<User> users = mapper.getUsers(map);
for (User user : users) {
System.out.println(user);
}
}
测试结果2:
Juint测试代码3
@Test
public void getUsers(){
SqlSession session = MybatisUtil.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("name","H");
map.put("id",1);
List<User> users = mapper.getUsers(map);
for (User user : users) {
System.out.println(user);
}
}
测试结果3:
02 缓存
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在SQL的映射文件中添加一行:
<cache/>
这个简单语句的效果如下:
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
注意事项: 缓存只作用于 cache 标签所在的映射文件中的语句。
cache 元素的属性
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这些属性配置表示创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
一般在执行查询的时候,才会使用缓存,使用的方法是:将useCache属性设为true
<select id="getUser" resultType="User" useCache="true">
select * from mybatis.user
</select>
使用缓存可以将查询出来的结果暂时保存着,如果短时间查询同样的语句比较多,使用缓存就可以提高查询速度,但是使用缓存会消耗内存资源。
缓存只作用于 cache 标签所在的映射文件中的语句。
在实际开发环境中,很少使用SQL层面的缓存来提高查询速度。