动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
在使用MyBatis过程中,有时我们的SQL是写在XML 映射文件中,如果写的SQL中有一些特殊的字符的话,在解析XML文件的时候会被当做XML自身元素,但我们不希望如此操作,所以我们要使用来解决。
<select id="gtBlogs" resultType="Blog">
<![CDATA[
select * from t_blog where id < #{blogId}
]]>
</select>
<sql id="extraSql">
`id`, `name`, `remark`, `create_by`, `create_at`, `update_by`, `update_at`
</sql>
<select id="selectOne" resultType="Employee">
select <include refid="extraSql"></include> from employee where emp_id = #{empId}
</select>
sql标签可以抽取sql片段,然后使用include标签将指定id的sql片段插入。
if标签:主要用于基本的if判断
JSP是用OGNL表达式进行解析的,mybatis的xml文件也是是用OGNL表达式解析。
其中 test 的表达式是基于OGNL 的表达式,语法规则也是OGNL的语法规则。
OGNL官方表达式手册:https://commons.apache.org/proper/commons-ognl/language-guide.html
注:在test中无法使用<= 等符号可以使用 lte 代替
< :lt
<=:lte
>:gt
>=:gte
<! -- trim()可以表示去除首位空格 -- >
<if test='order != null and "DESC".equalsIgnoreCase(order.trim())'>
xxxx
</if>
可以动态拼接sql条件。
<select id="findOne" resultType="Blog">
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
<if test="title != null and title != ''">
AND title = #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
<if test="age ==null or age ==''">
AND AGE = #{student.age}
</if>
</select>
可以按需更新需要个更新的字段。
<update id="updateSqlSet">
update demo_user
<set>
<if test="name !=null"> name=#{name},
<if test="age !=null"> age = #{age},
<if test="sex !=null"> sex = #{sex}
</set>
where id = #{id}
</update>
有点类似java中的switch,也有点像if-else
<select id="findOne" 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>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="findOne" resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
AND 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>
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
<update id="updateOne">
update Author
<set>
<if test="username != null">username=#{username},
<if test="password != null">password=#{password},
<if test="email != null">email=#{email},
<if test="bio != null">bio=#{bio}
</set>
where id=#{id}
</update>
trim可以替代where和set。
trim的属性:
<select id="selectDatas" resultType="Employee">
select * from employee
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="empId != null">
AND emp_id>#{empId}
</if>
<if test="empSalary != null">
AND emp_salary>#{empSalary}
</if>
</trim>
</select>
<update id="updateOne">
update Author
<trim prefix="SET" suffixOverrides=",">
<if test="username != null">username=#{username},
<if test="password != null">password=#{password},
<if test="email != null">email=#{email},
<if test="bio != null">bio=#{bio}
</trim>
where id=#{id}
</update>
bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
foreach常用于对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
<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>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。
@Update({""})
void updateAuthorValues(Author author);
也可以在Dao的java中直接使用注解标注sql语句
@Select("select * from t_job t where t.id = #{id}")
JobModel getById(Long id);
如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。
<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>