动态SQL作用:根据不同条件拼接 SQL 语句。
IF 标签
IF 语句用来判断某条件是否符合。若条件符合则拼接该 SQL,例如下面这个 SQL中的<if test="name != null">
的意思就是判断传入参数user
这个对象中是否包含了name
,如果包含name
就会通过 if 判断,拼接SQL,否则,将不会拼接AND name like #{name}
。
<select id="findByCondition" parameterType="user" resultType="user">
SELECT * FROM User tbl_user id = #{id}
<if test="name != null">
AND name like #{name}
</if>
</select>
WHERE 标签
上述的SQL中:WHERE id = #{id}
,表示该id
这个参数是必须要传入的,如果我们要将该条件也用 IF 包起来的话:
<select id="findByCondition" parameterType="user" resultType="user">
SELECT * FROM tbl_user WHERE
<if test="id != null">
id = #{id}
</if>
<if test="name != null">
AND name like #{name}
</if>
</select>
如果两个条件都不满足了,就会变成这样的 SQL,SELECT * FROM User WHERE
,导致 SQL 报错。
为解决问题,我们需要用到<WHERE>
标签,<WHERE>
元素只会在子元素返回任何内容的情况下才插入 WHERE 。这样就避免了两个条件都不满足的情况。
<select id="findByConditions" parameterType="user" resultType="user">
SELECT * FROM tbl_user
<where>
<if test="id != null">
id = #{id}
</if>
<if test="name != null">
AND name like #{name}
</if>
</where>
</select>
这里可能出现一个疑问:若第一个条件不满足,第二个条件满足呢?SQL 语句会变成了:SELECT * FROM User WHERE AND name like #{name}
,这又出现了问题,我们尝试一下:
...DEBUG er.UserMapper.findByConditions - ==> Preparing: SELECT * FROM tbl_user WHERE name like ?
看官网的介绍:<WHERE>
元素只会在子元素返回任何内容的情况下才插入 WHERE 。(这个我们已经知道到了) 若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。 所以,放心的使用<where>
标签吧。
TRIM 标签
该标签会提供一些属性,让你去自定义一些前缀,或者屏蔽掉某些内容。
- prefix :在整个标签【前面】附加指定内容。
- suffix :在整个标签【最后】追加指定内容。
- prefixOverrides :去掉【标签体内第一个指定】的关键字。
- suffixOverrides :去掉标【签体内最后一个指定】的关键字。
我们将上面的代码重新用<trim>
标签组织一下:
<where>
<if test="id != null">
id = #{id}
</if>
<if test="name != null">
AND name like #{name}
</if>
</where>
组织结果如下:
<trim prefix="where" prefixOverrides="AND">
<if test="id != null">
id = #{id}
</if>
<if test="name != null">
AND name like #{name}
</if>
</trim>
所以该标签很强大,不光可以实现<where>
同样的效果,<set>
也是如此。
CHOSE
条件中我只取一个,如果传过来的都不满足,那我设置一个保底。
<select id="findAdmin" parameterType="user" resultMap="user">
select * from tbl_user
<choose>
<when test="id != null and id != '">
where id = #{id};
</when>
<when test="name != null and name != ''">
where name = #{name};
</when>
<otherwise>
where name = '老程'
</otherwise>
</choose>
</select>
该SQL中只会取一个where
条件,如果前面的id
和name
都缺省了,那么就会默认查询name
为'老程'的管理员。
FOREACH
如果我的参数是一个列表,就像SQL语句的IN
操作,这就需要FOREACH
标签。
举个IN
的例子:
首先我们定义一个接口,设定一个方法:findAllUseForeach
,它的参数是传入一个数组,名字我限定使用@Param
修饰,该参数在XML文件中的别名叫ids
。
- Mapper接口:
List<User> findAllUseForeach(@Param("ids") List<String> ids);
在XML文件中,用parameterType
标明参数是列表类型;使用<fireach>
标签遍历整个数组参数,这里我们介绍一下属性的作用:
- collection:放传入参数(集合/数组)的名称。
- item:遍历(集合/数组)中每个元素,我们取个名字,例如这里,我们叫做:
id
。 - open:表示要用什么符号作为
foreach
标签的前缀。 - close:表示用什么符号作为
foreach
标签的后缀。 - separator:表示中间的
#{id}
是使用什么分隔符隔开。
- XML文件:
<select id="findAllUseForeach" parameterType="list" resultType="user">
select * from tbl_user
where id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
- 测试
@Test
public void findAllUseForeach() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<String> list = new ArrayList<>();
list.add("09ec5fcea620c168936deee53a9cdcfb");
list.add("09ec5fcea620c168936deee53a9cdcff");
List<User> allUseForeach = mapper.findAllUseForeach(list);
for (User useForeach : allUseForeach) {
System.out.println(useForeach);
}
}
这里再给出一个,单条的批量修改的SQL(传入的参数是一个:类转的Map),请自行学习其中的奥秘,关键信息已用注解标注
<!--键值对的 key 是 index ,value 是 item-->
<!--${key} 是引用属性,不能用#{},不然会以?占位,这里我们需要的是name = ?-->
<update id="updateUserByMap" parameterType="map">
update tbl_user
<foreach collection="beanMap" index="key" item="value" open="set " separator=",">
<if test="value != null">
${key} = #{value}
</if>
</foreach>
where id = #{id}
</update>
它的测试语句如下:
@Test
public void updateUserByMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("老四");
BeanMap beanMap = BeanMap.create(user);
System.out.println(beanMap);
// {birthday=null, name=老四, id=null, department=null, version=null, age=null}
Map<String, Object> departmentMap = new HashMap<>(2);
departmentMap.put("id", "09ec5fcea620c168936deee53a9cdcff");
departmentMap.put("beanMap", beanMap);
mapper.updateUserByMap(departmentMap);
sqlSession.commit();
}
BIND
bind
元素允许你在 SQL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:
<!--bind类似声明一个变量-->
<select id="findAllUserUseBind" parameterType="user" resultType="user">
<bind name="namelike" value="'%' + _parameter.getName() + '%'"/>
select * from tbl_user
where name like #{namelike}
</select>
通常用来简化处理模糊查询的%
拼接工作。
SET
SET标签非常简单,就是<set>
和<if>
的拼接,也可以用<trim>
替换相同的功能,就不展开介绍了,尝试一下是否掌握了吧~