本文根据mybatis官方网站的相关信息编写,相关资料请参考http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html
MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。mybatis支持if、choose (when, otherwise)、trim (where, set)、foreach、bind、多数据库支持和动态 SQL 中的可插拔脚本语言
1、if条件
动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。if条件中可以使用and或者or来拼接多个逻辑运算。比如:
<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>
2、choose (when, otherwise)
choose (when, otherwise)也是条件语句,相当于java中的switch(case, default)。例如
<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>
3、trim
trim通常用户where,set。作用是多个条件拼接SQL时,如果所有的if不满足或者有些if不满足会导致SQL语句不完整,结果执行SQL时报错。trim是用来规避这种事情发生的。例如:
<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>
select>
如果不使用trim进行where,则会出现如下的不完整的SQL语句
1、SELECT * FROM BLOG WHERE
2、SELECT * FROM BLOG WHERE AND title like '%abc%'
使用trim优化如下
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>//或者使用trim
<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>
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>
4、foreach
foreach对集合进行遍历,相当于java中的for。例如
<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>
SELECT * FROM POST P WHERE ID in(1,2,3)
5、bind
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
select>
6、多数据库支持
一个配置了“_databaseId”变量的 databaseIdProvider 可用于动态代码中,这样就可以根据不同的数据库厂商构建特定的语句。比如
<insert id="insert">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
<if test="_databaseId == 'oracle'">
select seq_users.nextval from dual
if>
<if test="_databaseId == 'db2'">
select nextval for seq_users from sysibm.sysdummy1"
if>
selectKey>
insert into users values (#{id}, #{name})
insert>
7、动态 SQL 中的可插拔脚本语言
MyBatis 从 3.2 开始支持可插拔脚本语言,这允许你插入一种脚本语言驱动,并基于这种语言来编写动态 SQL 查询语句。
可以通过实现以下接口来插入一种语言:
public interface LanguageDriver {
ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}
一旦设定了自定义语言驱动,你就可以在 mybatis-config.xml 文件中将它设置为默认语言:
<typeAliases>
<typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
typeAliases>
<settings>
<setting name="defaultScriptingLanguage" value="myLanguage"/>
settings>
除了设置默认语言,你也可以针对特殊的语句指定特定语言,可以通过如下的 lang 属性来完成:
<select id="selectBlog" lang="myLanguage">
SELECT * FROM BLOG
select>
或者,如果你使用的是映射器接口类,在抽象方法上加上 @Lang 注解即可:
public interface Mapper {
@Lang(MyLanguageDriver.class)
@Select("SELECT * FROM BLOG")
List<Blog> selectBlog();
}
注意: 可以将 Apache Velocity 作为动态语言来使用,更多细节请参考 MyBatis-Velocity 项目。
你前面看到的所有 xml 标签都是由默认 MyBatis 语言提供的,而它由别名为 xml 的语言驱动器 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver 所提供。