MyBatis 动态SQL
Mybatis的强大特性之一便是它的动态SQL。
利用动态SQL可以解决根据不同条件拼接SQL语句这一问题,如果你有过JDBC或其他类似框架的经验,你就能体会到这种根据不同条件拼接 SQL 语句有多么麻烦,拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。所以,动态SQL通俗点说就是用一种比上述方法简单的方式将SQL语句拼接在一起,而且省去了很多麻烦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
常用的四种:
if
choose(when,otherwise)
trim(where)
foreach
1,if
动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。比如:
<select id="findStuNameByClass" parameterType="int" resultType="Student">
SELECT * from student
<where>
<if test="stuid!=0">
stuid=#{stuid}
</if>
<if test="sname!=null">
and sname like concat(concat('%',#{sname}),'%')
</if>
</where>
</select>
上述代码里的语句提供了一个可选的查找类型的功能。如果传入的stuid不为空,则执行第一个if,如果传入的stuid为空,这执行第二个if,它有点像Java中的if else语句。
2,choose(when,otherwise)
有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch-case 语句。
<select id="findStudentByChoose" resultType="Student">
SELECT * FROM student where 1=1
<choose>
<when test="sname!=null and sname!=''">
AND sname LIKE concat(concat('%',#{sname}),'%')
</when>
<when test="age!=0">
AND age>#{age}
</when>
<otherwise>
AND stuid=#{stuid}
</otherwise>
</choose>
</select>
这里提供了三种方式,符合哪一种就根据哪一种来执行查询操作,但需要注意的是如果有一条符合,则不会去执行下面的语句,比如sname不为空,则执行第一when,后面的将不再执行。
3,trim(where)
前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。但是看下面的例子。
<select id="findStuNameByClass" parameterType="int" resultType="Student">
SELECT * from student
<if test="stuid!=0">
stuid=#{stuid}
</if>
<if test="sname!=null">
and sname like concat(concat('%',#{sname}),'%')
</if>
</select>
如果这些条件没有一个能匹配上将会怎样?最终这条 SQL 会变成这样:
SELECT * from student where
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
SELECT * from student where and sname like concat(concat('%',#{sname}),'%')
很显然,这也是一个错误的SQL语句,所以这个问题不能简单的用条件句式来解决
MyBatis 有一个简单的处理,这在90%的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作
<select id="findStuNameByClass" parameterType="int" resultType="Student">
SELECT * from student
<where>
<trim suffix="" suffixOverrides="and">
<if test="stuid!=0">
stuid=#{stuid}
</if>
<if test="sname!=null">
and sname like concat(concat('%',#{sname}),'%')
</if>
</trim>
</where>
</select>
where 元素知道只有在一个以上的if条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
4,foreach
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tb.mapper.StudentMapper">
<!--根据数组来找-->
<select id="findStudentByArray" resultType="Student">
SELECT * FROM student WHERE stuid IN
<foreach collection="array" item="stuid" open="(" separator="," close=")">
#{stuid}
</foreach>
</select>
<!--根据列表来找-->
<select id="findStudentByList" resultType="Student">
SELECT * FROM student WHERE stuid IN
<foreach collection="list" item="stuid" open="(" separator="," close=")">
#{stuid}
</foreach>
</select>
<!--根据map来找-->
<select id="findStudentByMap" resultType="Student">
SELECT * FROM student WHERE sname like concat(concat('%',#{sname}),'%') and stuid in
<foreach collection="list" item="map" open="(" separator="," close=")">
#{map}
</foreach>
</select>
</mapper>
注意 你可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以"list"作为键,而数组实例的键将是"array"。