动态sql
主要用于解决查询条件不确定的情况:在程序运行期间,根据提交的查 询条件进行查询。
通过MyBatis提供的各种标签对条件作出判断以实现动态拼接SQL语句。
MyBatis的动态SQL是基于OGNL表达式的。
使用动态SQL的原因
提供的查询条件不同,执行的SQL语句不同。若将每种可能的情况均逐一 列出,就将出现大量的SQL语句。
MyBatis中用于实现动态SQL的元素主要有:
if语句
where
trim
set
foreach
choose(when,otherwize)
if标签
就是简单的条件判断,利用if语句我们可以实现某些简单的条件选择。
where标签
会在写入where元素的地方输出一个where,
不需要考虑where元素里面的条件输出是什么样子的,MyBatis会智能的 处理
如果所有的条件都不满足,那么MyBatis就会查出所有的记录
如果输出后是and开头的,MyBatis会把第一个and忽略
如果是or开头的,MyBatis也会把它忽略
在where标签中不需要考虑空格的问题,MyBatis会智能的加上
<select id="selectByNamePassword" parameterType="user" resultType="user">
select * from user
<where>
<if test="name!=null and name!=''">
and name like concat('%',#{name},'%')
</if>
<if test="password!=null and password!=''">
and password=#{password}
</if>
</where>
</select>
trim标签的主要功能是可以在自己包含的内容前加上某些前缀,也可 以在其后加上某些后缀,与之对应的属性是prefix和suffix;
可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些 内容覆盖,对应的属性是prefixOverrides和suffixOverrides;
<insert id="insertSelective" parameterType="user">
insert into user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id!=null">
id,
</if>
<if test="name!=null ">
name,
</if>
<if test="password!=null">
password,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id!=null">
#{id},
</if>
<if test="name!=null ">
#{name},
</if>
<if test="password!=null">
#{password},
</if>
</trim>
</insert>
set标签主要是用在更新操作的时候,它的功能和where标签差不多。
当update语句中没有使用if标签时,如果有一个参数为null,都会导 致错误。
当在update语句中使用if标签时,如果前面的if没有执行,则会导致 逗号多余错误。
使用set标签可以在包含的语句前输出一个set,然后如果包含的语句 是以逗号结束的话将会把该逗号忽略。
<update id="updateByPrimaryKeySelective" parameterType="com.zx.domain.User">
update user
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="password != null">
password = #{password,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
foreach 标签
foreach标签主要用在构建in条件中,它可以在SQL语句中进行迭代一 个集合。
foreach标签的属性主要有 item,index,collection,open, separator,close。
item表示集合中每一个元素进行迭代时的别名
index指定一个名字,用于表示在迭代过程中,每次迭代到的位置
open表示该语句以什么开始
separator表示在每次进行迭代之间以什么符号作为分隔符
close表示以什么结束
foreach标签的collection属性是必须指定的,但是在不同情况下, 该属性的值是不一样的,
主要有以下3种情况:
1.如果传入的是单参数且参数类型是一个List的时候,collection属性值 为list
2.如果传入的是单参数且参数类型是一个array数组的时候,collection的 属性值为array
3.如果传入的参数是多个的时候,需要把它们封装成一个Map,当然单参数 也可以封装成Map
4.实际上如果在传入参数的时候,在MyBatis里面也是会把它封装成一个 Map的,Map的key就是参数名,所以这个时候collection属性值就是传入 的List或Array对象在自己封装的Map里面的key
<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>
choose 标签
choose标签 按顺序判断其内部when标签中的test条件出否成立,如果有一个成立, 则 choose 结束。
当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的 sql。
类似于Java 的 switch 语句,choose 为 switch,when 为 case, otherwise 则为 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>
关于动态SQL的接口和类
SqlNode接口,简单理解就是xml中的每个标签,比如上述sql的update,trim,if标签:
public interface SqlNode {
boolean apply(DynamicContext context);
}
SqlSource Sql源接口,代表从xml文件或注解映射的sql内容,主要就是用于创建BoundSql,有实现类DynamicSqlSource(动态Sql源),StaticSqlSource(静态Sql源)等:
public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}
BaseBuilder接口及其实现类(属性,方法省略了),这些Builder的作用就是用于构造sql:
XMLConfigBuilder:解析mybatis中configLocation属性中的全局xml文件,内部会使用XMLMapperBuilder解析各个xml文件。
XMLMapperBuilder:遍历mybatis中mapperLocations属性中的xml文件中每个节点的Builder,比如user.xml,内部会使用XMLStatementBuilder处理xml中的每个节点。
XMLStatementBuilder:解析xml文件中各个节点,比如select,insert,update,delete节点,内部会使用XMLScriptBuilder处理节点的sql部分,遍历产生的数据会丢到Configuration的mappedStatements中。
XMLScriptBuilder:解析xml中各个节点sql部分的Builder。