mybatis的SQL 映射文件中的顶级元素:
- cache – 对给定命名空间的缓存配置。
- cache-ref – 对其他命名空间缓存配置的引用。
- resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
- sql – 可被其他语句引用的可重用语句块。
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
其中我们常用的是insert、update、delete、select,而sql和resultMap作为sql映射的辅助元素和结果映射元素,也经常被用到。下面我们就来看一下这几种元素在mapper.xml文件中的使用场景以及动态SQL的使用。
mybatis中常用的动态SQL标签有:
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
1、if
if标签的使用格式为:<if test=""> context..... </if>,如果test中的条件为真,则会将if标签下的内容拼接入sql语句中。
<select id="selectManLike" resultType="Man">
SELECT * FROM MAN 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)的使用格式为:
<choose> <when test=""> context</when> <when test="">context </when> .... <otherwise>context</otherwise> </choose>
这样看choose (when, otherwise)的使用于if标签的使用差不多,而choose (when, otherwise)的使用看上去好像更加繁琐。实际上if标签与choose (when, otherwise)的功能上也有差异,if标签会处理所有符合条件的test语句;而choose (when, otherwise)则只选择其中一个满足条件的test语句,且是先到先得策略。
<select id="selectManLike" resultType="Man">
SELECT * FROM Man 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 (where, set)
回到我们上面的if标签中的示例语句,如果我们将它改成下面这样的语句
<select id="selectManLike" resultType="Man">
SELECT * FROM MAN WHERE
<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>
</select>
那么,如果我们传入的所有参数都为null,这时mybatis编译出的sql语句就类似为:select * from man where ,这样的sql语句肯定是无法执行的。且如果state为null,其他条件不是null,则输出的sql语句为:select * from man where and title..... 这样的SQL语句也是无法执行的。为此也就有了trim (where, set)。
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号。where元素用于条件筛选,set元素用于update语句。如果想自定义where和set元素的功能,我们可以通过自定义 trim 元素来定制 where 、set元素的功能。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
4、foreach
<foreach collection="list" item="item" index="index" open="(" separator="," close=")"> #{item} </foreach>
这是foreach标签的使用格式和所有属性,可以根据需要自己选择去留一些属性,但是collection和item两个属性是必须的。而这些属性所代表的含义为:
- collection表示便利的集合类型或者集合名
- item表示集合中每一个元素进行迭代时的别名
- index用于表示在迭代过程中,每次迭代到的位置
- open表示该语句以什么开始
- separator表示在每次进行迭代之间以什么符号作为分隔 符
- close表示以什么结束
下面介绍一下foreach的几种应用场景:
(1)请求参数是List<String>等基本数据类型集合
long delMans(List<String> ids)
<delete id="delMans">
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
(2)请求参数是List<Man>等复杂对象集合类型
long addMans(List<Man> manList)
对应mapper.xml中的标签:
<insert id="addMans" resultType="long">
insert into man values
<foreach collection="list" item="man" open="" separator="" close="">
#{man.id},#{man.name},#{man.age}
</foreach>
</insert>
(3)请求参数是对象,对象中包含有集合类型数据,如:
@Data
public class User{
private String id;
private String parentId;
private List<User> children;
}
void insertUser(User user);
<insert id="insertUser">
insert into user values
(#{id},#{parentId}),
<foreach collection="children" item="user" separator=",">
(#{user.id},#{user.parentId})
</foreach>
</insert>
(4)传递多个参数,其中一个或多个是集合类型
这种情况只需要使用@Param注解指定传递的参数名即可,其它与上面的使用基本相同。
List<User> getUser(@Param("name")String name, @Param("ids") List<String> idList)