- 参考自官方文档
一、概述
- 动态 SQL 是 MyBatis 的强大特性之一。
- 通过动态 SQL,可以实现动态地拼接SQL语句,实现无需修改或创建多个标签,即可实现多种功能。
二、if
- 只有当
if
标签内的条件满足,才会将if标签的内容拼接到SQL语句中<select id="selectBlogByIf" parameterType="map" resultType="blog"> select id, name, author, release_date, view from blog <where> <if test="id != null"> id = #{id} </if> <if test="view != null"> and view >= #{view} </if> </where> </select>
@Test public void selectBlogByIfTest() { try (SqlSession sqlSession = Utils.getSqlSession()) { BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map map = new HashMap(); map.put("id", 1); //map.put("view", 10); List<Blog> blogs = mapper.selectBlogByIf(map); blogs.forEach(logger::info); } }
- 当map中只添加了
id
键,那就会生成语句where id = #{id}
;如果只添加了view
键,那就生成语句where view = #{view}
;两个都添加了就生成语句where id = #{id} and view = #{view}
;如果啥都没加,那就啥筛选条件都没有
- 当map中只添加了
三、choose、when、otherwise
- 实现从多个条件中选择一个,类似于Java的
switch-case
<select id="selectBlogByChoose" parameterType="map" resultType="blog"> select id, name, author, release_date, view from blog <where> <choose> <when test="id != null"> id = #{id} </when> <when test="name != null"> name = #{name} </when> </choose> </where> </select>
@Test public void selectBlogByChooseTest() { try (SqlSession sqlSession = Utils.getSqlSession()) { BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map map = new HashMap(); //map.put("id", 2); map.put("name", "10"); List<Blog> blogs = mapper.selectBlogByChoose(map); blogs.forEach(logger::info); } }
四、trim、where、set
- 为了实现无论是否增加筛选条件,都可以成功运行,可以将
where
提取出来作为标签,只有在where
内的内容存在的时候,才添加where
。详见以上例子。 where
元素只会在子元素返回任何内容的情况下才插入WHERE
子句。而且,若子句的开头为AND
或OR
,where
元素也会将它们去除set
元素会动态地在行首插入SET
关键字,并会删掉额外的逗号<update id="updateBlog" parameterType="map"> update blog <set> <if test="name != null"> name = #{name}, </if> <if test="author != null"> author = #{author}, </if> <if test="release_date"> name = #{releaseDate}, </if> <if test="view != null"> view = #{view}, </if> </set> <where> <if test="id != null"> id = #{id} </if> </where> </update>
@Test public void updateBlogTest() { try (SqlSession sqlSession = Utils.getSqlSession()) { BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map map = new HashMap(); map.put("id", 1); map.put("view", 10); //map.put("author", "张三"); map.put("name", "python"); //map.put("releaseDate", LocalDate.now()); int res = mapper.updateBlog(map); sqlSession.commit(); if (res > 0) logger.info("修改成功"); else logger.info("修改失败"); } }
- 如果
where
元素与你期望的不太一样,你也可以通过自定义trim
元素来定制where
元素的功能。比如,和where
元素等价的自定义trim
元素为
等效于<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
set
<trim prefix="SET" suffixOverrides=","> ... </trim>
prefix
表示如果内容存在就在插入的在句子开头的内容;suffix
表示如果内容存在就在插入的在句子末尾的内容;prefixOverrides
表示如果内容的开头存在,就删除的部分;suffixOverrides
表示如果内容的末尾存在,就删除的部分。
五、foreach
- 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建
IN
条件语句的时候)<select id="selectBlogsByIds" resultType="blog" parameterType="list"> select * from blog where id in <foreach item="id" collection="list" open="(" separator="," close=")"> #{id} </foreach> </select>
item
表示集合每个元素的名称,open
为开始符号、close
为结束符号,separator
为分隔符@Test public void selectBlogsByIdsTest() { try (SqlSession sqlSession = Utils.getSqlSession()) { BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); List<Blog> blogs = mapper.selectBlogsByIds(Arrays.asList(1, 2, 3)); blogs.forEach(logger::info); } }
- 批量插入
int insertAll(@Param("users") List<User> users);
<insert id="insertAll"> insert user(id, name, address) values <foreach collection="users" item="user" separator=","> (#{user.id}, #{user.name}, #{user.address}) </foreach> </insert>
@Test public void testInsertAll() { List<User> users = new ArrayList<>(); for (int i = 0; i < 1000; i++) { users.add(new User(i + 1, UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID().toString().substring(0, 10))); } try (SqlSession sqlSession = Utils.getSqlSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); int res = mapper.insertAll(users); sqlSession.commit(); if (res > 0) System.out.println("插入成功"); else System.out.println("插入失败"); } }
六、script
- 要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素(注解开发配置,详见注解开发)
@Update({"<script>", "update blog", "<set>", "author = #{author}", "</set>", "where id = #{id}", "</script>" }) int updateAuthorValues(@Param("author") String author, @Param("id") int id);
七、bind
bind
在标签内允许创建一个变量,提前预处理好变量,再放进语句内拼接,常用于模糊查询<select id="selectBlogsByFuzzyQuery" resultType="blog" parameterType="string"> <bind name="pattern" value="'%' + content + '%'"/> select * from blog where author like #{pattern} </select>
将模糊查询包含
content
内容@Test public void selectBlogsByFuzzyQueryTest() { try (SqlSession sqlSession = Utils.getSqlSession()) { BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); List<Blog> zhang = mapper.selectBlogsByFuzzyQuery("张"); zhang.forEach(logger::info); } }