MyBatis 动态SQL优点
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦,拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
1. if
2. choose (when, otherwise)
3. trim (where)
4. foreach
5. bind(不常用)
动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分,例如
<select id="getByDept" resultType="City">
select * from provice
<where>
<if test="pid!=null">
pid=#{pid}
</if>
</where>
</select>
当满足if中的条件是就会把if中条件也加入进sql语句中,否则不会。例如当pid不能与null时,就会查找provice表中pid为传入的值的数据,但是当pid=null时,就会查找provice表中的所有数据。
<select id="findStudentByChoose" resultType="City">
SELECT * from city where 1=1
<choose>
<when test="cname!=null and cname!=''">
and cname like concat(concat('%',#{cname}),'%')
</when>
<when test="pid!=0">
and pid=#{pid}
</when>
<otherwise>
<!-- 这里可以写,也可以不写代码-->
</otherwise>
</choose>
</select>
这里提供了两种选择方式,你可以选择根据cname来查找,也可以选择根据pid来查找,但只要满足一个条件,其他条件则自动选择不满足,这样也可以避免无意义的查找。(上面的1=1也可以不写,但是需要加入其他的东西,下面会提到)
前面例子已经合宜地解决了动态 SQL 问题,但是看下面的例子
<select id="getByDept" resultType="City">
select * from provice where
<if test="pid!=null">
pid=#{pid} and
</if>
<if test="cname!=null and cname!=''">
and pname like concat(concat('%',#{cname}),'%')
</if>
</select>
当没有一个条件满足时,这会变成
select * from provice where
这样的sql语句并不正确,另外当第一个条件不满足,第二个条件满足时则会变成
select * from provice where
and pname like concat(concat('%',#{cname}),'%')
这个查询也会失败。这个问题不能简单的用条件句式来解决,这个时候我们就可以选择使用trim(where)
<select id="getByDept" resultType="City">
select * from provice where
<trim suffix="" suffixOverrides="and">
<if test="pid!=null">
pid=#{pid} and
</if>
<if test="cname!=null and cname!=''">
and pname like concat(concat('%',#{cname}),'%')
</if>
</trim>
</select>
where 元素知道只有在一个以上的if条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
如果 where 元素没有按正常套路出牌,我们还是可以通过自定义 trim 元素来定制我们想要的功能。
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
注意 你可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以"list"作为键,而数组实例的键将是"array"。
例如
<!--根据数组来找-->
<select id="findStudentByArray" resultType="City">
SELECT * from city where pid in
<foreach collection="array" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
<!--根据列表来找-->
<select id="findStudentByList" resultType="City">
select * from city WHERE pid in
<foreach collection="list" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
<!--根据map来找-->
<select id="findStudentByMap" resultType="City">
SELECT * from city where cname like concat(concat('%',#{cname}),'%') and pid in
<!--这里的name则根据前面传入的key值来确定-->
<foreach collection="name" item="map" open="(" separator="," close=")">
#{map}
</foreach>
</select>
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。例如
<select id="bind" resultType="Provice">
<bind name="pro" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM porvice
WHERE pid LIKE #{pro}
</select>