0.数据库准备
新建一个表并初始化数据。
create table activebooks(UUID varchar(36) primary key,name varchar(20),type varchar(10),author varchar(10))
insert into mybatis.activebooks
VALUES (UUID(), 'book1', 1, '小明'),
(UUID(), 'book2', 1, '小红'),
(UUID(), 'book3', 2, '小明'),
(UUID(), 'book4', 2, '小红')
当然,对于实体类等需要重新搭建的在前文已经说明如何搭建,这里不再赘述。
1.IF
现有这样一个需求:查询指定类型和作者的图书信息。但需要注意的是,希望如果查询时不输入类型就只根据作者查询,反之亦然。
我们知道,如果两个参数都传的话,SQL语句应该是这样的:
select * from activebooks where author='小明' and type=1
如果说不传作者参数、只传类型参数的话,SQL语句应该变成这样:
select * from activebooks where type=1
也就是说在MyBatis中, author=#{}这句话不应该输出。
MyBatis提供了IF标签实现这种操作。
<select id="ifTest" resultType="pojo.Books">
select * from mybatis.activebooks where 1=1
<if test="author != null">and author=#{author}</if>
<if test="type != null">and type=#{type}</if>
</select>
IF标签的作用是判断test中的条件,比如Line 3是判断author如果不为空,就拼接后面的语句。
这里的 where 1=1 的作用为便于后两行and的拼接,如果没有 1=1 的判断的话,这句话就变成了 where and,这句SQL语句是错的(where不能直接接and),所以使用1=1(也就是一定为真的语句)来避免对and的麻烦处理。
使用测试类进行测试。
如果想要查看最后执行的语句,需要使用日志工具(比如log4j等)输出日志即可。
2.WHERE
上面的例子使用了1=1来处理and(or同理)可能存在的潜在问题。当然MyBatis也提供了where标签来更好的解决这一问题。
将上例的SQL改写:
<select id="ifTest" resultType="pojo.Books">
select * from mybatis.activebooks
<where>
<if test="author != null">and author=#{author}</if>
<if test="type != null">and type=#{type}</if>
</where>
</select>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
3.SET
同理,当进行update更新操作时会用到set。
现有需求:更新author和type,如果传参则更改,如果不传则不变。
SQL语句如下:
<update id="setTest" parameterType="pojo.Books">
update mybatis.activebooks
<set>
<if test="type != null">type = #{type},</if>
<if test="author != null">author = #{author}</if>
</set>
where name = #{name};
</update>
当然,这里在写接口和测试类的时候会有变化,可以先自行尝试调整(关于返回值问题和输出问题), 如果没有头绪或者测试失败请看示例接口和测试类。
void setTest(@Param("author") String author,@Param("type") String type,@Param("name")String name);
@Test
public void setTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
mapper.setTest(null,"2","book2");
sqlSession.commit();
sqlSession.close();
}
使用上述代码测试:<br /><br />
4.CHOOSE
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
现有需求:查询指定类型和作者的图书信息。但需要注意的是,希望如果查询时不输入类型就只根据作者查询,反之亦然。但是当两者都没有传参的时候就查询出book1一条结果。
SQL语句如下:
<select id="chooseTest" resultType="pojo.Books">
select * from mybatis.activebooks
<where>
<choose>
<when test="author != null">author=#{author}</when>
<when test="type != null">and type=#{type}</when>
<otherwise>and name='book1'</otherwise>
</choose>
</where>
</select>
使用上述代码测试,注意观察传参和拼接出的SQL语句的关系:



通过上面的测试用例,不难发现,当两个参数都传的情况下的结果和只传第一项结果是相同的。这也体现了为什么说有点类似Java的switch语句。
5.FOREACH
动态 SQL 的另一个常见使用场景是对集合进行遍历。 foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
官方文档的说明貌似有点云里雾里,其实简单来说就是实现遍历功能。
比如说这样一个需求:需要查询名称分别为book1、book2、book3的具体信息。
如果只是写SQL的话,大体应该是这样:
select * from mybatis.activebooks where name='book1' or name='book2' or name='book3'
那么使用foreach这样实现:
<select id="forEachTest" parameterType="map" resultType="pojo.Books">
select * from mybatis.activebooks
<where>
<!--说明摘自狂神说
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
-->
<foreach collection="names" item="name" open="and (" close=")" separator="or">
name=#{name}
</foreach>
</where>
</select>
注:这里接口的参数用的是map
编写测试类测试:
@Test
public void forEachTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
HashMap map = new HashMap();
List<String> names = new ArrayList<String>();
names.add("book1");
names.add("book2");
names.add("book3");
map.put("names",names);
List<Books> books=mapper.forEachTest(map);
System.out.println(books);
sqlSession.close();
}


