一, 引言
在之前的 CRUD 例子中, 都是一些很简单的 SQL, 然而实际的业务开发中会有一些复杂的 SQL, 我们经常需要拼接 SQL, 拼接的时候要确保不能忘了必要的空格, 还要注意省掉列名列表最后的逗号. Mybatis 个一个强大特性 -- 动态 SQL, 这一特性可以彻底摆脱这种痛苦.
二, if 标签
现在有如下查询:
- <!-- 根据条件查询用户 -->
- <select id="queryUserByWhere" parameterType="user" resultType="user">
- SELECT id, username, birthday, sex, address FROM `user`
- WHERE sex = #{sex} AND username LIKE
- '%${username}%'
- </select>
当我们带入两个参数时, 返回结果不会有问题, 可是当我们只带入姓名, 不带入性别时, 结果就不合理, 因为 sex 带入的 null, 作为查询条件就过滤了结果, 这个时候我们需要 if 标签.
改造 sql:
- <!-- 根据条件查询用户 -->
- <select id="queryUserByWhere" parameterType="user" resultType="user">
- SELECT id, username, birthday, sex, address FROM `user`
- WHERE 1=1
- <if test="sex!=null and sex !=''">
- AND sex = #{sex}
- </if>
- <if test="username!=null and username!=''">
- AND username like
- '%${username}%'
- </if>
- </select>
将接口和方法都加入其中
- @Test
- public void testQueryUserByWhere() {
- // mybatis 和 spring 整合, 整合之后, 交给 spring 管理
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- // 创建 Mapper 接口的动态代理对象, 整合之后, 交给 spring 管理
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- // 使用 userMapper 执行根据条件查询用户
- User user = new User();
- //user.setSex("1");
- user.setUsername("张");
- List<User>list = userMapper.queryUserByWhere(user);
- for (User u : list) {
- System.out.println(u);
- }
- // mybatis 和 spring 整合, 整合之后, 交给 spring 管理
- sqlSession.close();
- }
结果:
三, where 标签
where 标签会把第一个 and 忽略, 当然如果是 or 开头的, MyBatis 也会把它忽略, 此外, 在 where 元素中你不需要考虑空格的问题, MyBatis 会智能的帮你加上.
- <select id="queryUserByWhere1" parameterType="user" resultType="user">
- SELECT id, username, birthday, sex, address FROM `user`
- <!-- where 标签可以自动添加 where, 同时处理 sql 语句中第一个 and 或者 or 关键字 -->
- <where>
- <if test="sex!=null">
- AND sex = #{sex}
- </if>
- <if test="username!=null and username!=''">
- AND username like
- '%${username}%'
- </if>
- </where>
- </select>
四, set 标签
在更新的时候我们也需要像 where 一样能够进行动态判断, 这个时候就使用 set 标签, set 会使最后的逗号忽略, 我们就可以动态的更新那些修改了的字段.
如下:
- <update id="dynamicSetTest" parameterType="user">
- update `user`
- <set>
- <if test="sex != null">
- sex = #{sex},
- </if>
- <if test="username!=null and username!=''">
- username = #{username},
- </if>
- </set>
- where id = #{id}
- </update>
测试:
- @Test
- public void dynamicSetTest() {
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- User user = new User();
- //user.setSex("1");
- user.setUsername("袁大大");
- user.setId(26);
- userMapper.dynamicSetTest(user);
- sqlSession.commit();
- sqlSession.close();
- }
五, choose(when,otherwise) 标签
choose 的作用类似 Java 语言中的 switch, 可以解决我们只想选择一个查询条件的情况.
如下:
- <select id="selectUserByChoose" resultType="user" parameterType="user">
- select id, username, birthday, sex, address FROM `user`
- <where>
- <choose>
- <when test="id !='' and id != null">
- id=#{id}
- </when>
- <when test="username !='' and username != null">
- and username like #{username}
- </when>
- <otherwise>
- and sex=#{sex}
- </otherwise>
- </choose>
- </where>
- </select>
这个写法很容易理解, 与 switch 相同, 匹配成功后就会跳出.
六, trim 标签
trim 标记是一个格式化的标记, 可以完成 set 或者是 where 标记的功能, 怎么用呢:
增加 prefix 前缀, 去掉第一个 prefixoverride 中内容.
增加 suffix 后缀, 去掉最后一个 suffixoverride 中内容.
通过 trim 可以解决 where 与 set 问题
- <select id="selectUserByUsernameAndSex" resultType="user" parameterType="user">
- select * from user
- <!-- <where>
- <if test="username != null">
- username=#{username}
- </if>
- <if test="username != null">
- and sex=#{sex}
- </if>
- </where> -->
- <trim prefix="where" prefixOverrides="and | or">
- <if test="username != null">
- and username=#{username}
- </if>
- <if test="sex != null">
- and sex=#{sex}
- </if>
- </trim>
- </select>
先增加 where, 并去掉第一个 and 或者 or , 替换了 where if 写法.
- <!-- 根据 id 更新 user 表的数据 -->
- <update id="updateUserById" parameterType="com.ys.po.User">
- update user u
- <!-- <set>
- <if test="username != null and username !=''">
- u.username = #{username},
- </if>
- <if test="sex != null and sex !=''">
- u.sex = #{sex}
- </if>
- </set> -->
- <trim prefix="set" suffixOverrides=",">
- <if test="username != null and username !=''">
- u.username = #{username},
- </if>
- <if test="sex != null and sex !=''">
- u.sex = #{sex},
- </if>
- </trim>
- where id=#{id}
- </update>
增加 set, 并去掉最后一个逗号, 替换了 set if 写法.
七, SQL 片段
写 sql 时经常会出现一些重复片段, 我们可以进行提取, 这样可以做到重用.
先使用 sql 进行声明:
- <!-- 声明 sql 片段 -->
- <sql id="userFields">
- id, username, birthday, sex, address
- </sql>
使用 include refid:
- <select id="queryUserBySqlWhere" parameterType="user" resultType="user">
- <!-- SELECT id, username, birthday, sex, address FROM `user` -->
- <!-- 使用 include 标签加载 sql 片段; refid 是 sql 片段 id -->
- SELECT <include refid ="userFields"/> FROM `user`
- <!-- where 标签可以自动添加 where 关键字, 同时处理 sql 语句中第一个 and 关键字 -->
- <where>
- <if test="sex != null">
- AND sex = #{sex}
- </if>
- <if test="username != null and username !=''">
- AND username LIKE
- '%${username}%'
- </if>
- </where>
- </select>
八, foreach 标签
当我们向 sql 传递数组或 List,mybatis 使用 foreach 解析.
foreach 标签, 进行遍历
collection: 遍历的集合, 这里是 QueryVo 的 ids 属性
item: 遍历的项目, 可以随便写,, 但是和后面的 #{} 里面要一致
open: 在前面添加的 sql 片段
close: 在结尾处添加的 sql 片段
separator: 指定遍历的元素之间使用的分隔符
- <select id="queryUserByIds" parameterType="com.yuanqinnan.pojo.QueryVo" resultType="user">
- SELECT * FROM `user`
- <where>
- <foreach collection="ids" item="item" open="id IN (" close=")"
- separator=",">
- #{item}
- </foreach>
改造 QueryVo:
- @Data
- public class QueryVo {
- private User user;
- private List<Integer> ids;
- }
测试方法:
- @Test
- public void queryUserByIds(){
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- QueryVo user = new QueryVo();
- List<Integer>ids = new ArrayList<>();
- ids.add(1);
- ids.add(10);
- ids.add(24);
- user.setIds(ids);
- List<User> list = userMapper.queryUserByIds(user);
- for (User u : list) {
- System.out.println(u);
- }
- sqlSession.close();
- }
结果
动态 sql 其实是一个拼接过程, 我们掌握上面这些标签, 就能完成 mybatis 的动态 sql
来源: https://www.cnblogs.com/yuanqinnan/p/10712679.html