Loading... # **Mybatis动态SQL** ## **目标** 1. **了解mybatis的动态SQL** 2. **了解并学会使用IF-WHERE 动态sql语句** 3. **了解并学会使用SET 动态sql语句** 4. **了解并学会使用SQL片段 动态sql语句** 5. **了解并学会使用Foreach 动态sql语句** ## **一、介绍** **什么是动态SQL:******动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.**** > **官网描述:**** > ****MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。**** > ****虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。** **我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。** **那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。** ## **二.、环境准备** ### **1. 创建数据库,新建一个blog表** ``` DROP TABLE IF EXISTS `blog`; CREATE TABLE `blog` ( `id` int(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT COMMENT '博客id', `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '博客标题', `author` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '博客作者', `create_time` datetime(0) NOT NULL COMMENT '创建时间', `views` int(30) NOT NULL COMMENT '浏览量', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1; ``` ### **2. 实体类编写** ``` @Data public class Blog { private String id; private String title; private String author; private Date createTime; private int views; } ``` ### **3. 编写Mapper接口和xml文件** ``` /** *功能描述: 新增一篇博客 * @param blog 博客试题 * @return int * @author jiaoqianjin * @date 2021/3/9 */ int addBlog(Blog blog); ``` ``` <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.shida.mapper.BlogMapper"> </mapper> ``` ### **4. 插入初始数据** **编写接口** ``` /** *功能描述: 新增一篇博客 * @param blog 博客试题 * @return int * @author jiaoqianjin * @date 2021/3/9 */ int addBlog(Blog blog); ``` **编写xml** ``` <!--注意配置别名--> <insert id="addBlog" parameterType="blog"> insert into blog (id, title, author, create_time, views) values (#{id},#{title},#{author},#{createTime},#{views}); </insert> ``` **初始化博客** ``` @Test public void addInitBlog(){ SqlSession session = MybatisUtil.getSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setTitle("Mybatis"); blog.setAuthor("焦前进"); blog.setCreateTime(new Date()); blog.setViews(9999); mapper.addBlog(blog); blog.setTitle("Spring"); mapper.addBlog(blog); blog.setTitle("SpringMVC"); mapper.addBlog(blog); session.close(); } ``` ## **三、IF-WHERE语句** ****需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询**** ### **1. 编写参数实体类** ``` @Data public class BlogDTO { private String title; private String author; } ``` ### **2.编写接口类** ``` /** *功能描述: 根据条件查询 * @param blogDTO 参数 * @return java.util.List<com.shida.entity.Blog> * @author jiaoqianjin * @date 2021/3/9 */ List<Blog> queryBlogIf(BlogDTO blogDTO); ``` ### **3.编写xml** ``` <!--需求1: 根据作者名字和博客名字来查询博客! 如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询 select * from blog where title = #{title} and author = #{author} --> <select id="queryBlogIf" parameterType="blogDTO" resultType="blog"> select * from blog <where> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where> </select> ``` ### **4. 测试** ``` @Test public void testQueryBlogIf(){ SqlSession session = MybatisUtil.getSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); BlogDTO blogDTO = new BlogDTO(); blogDTO.setTitle("Mybatis"); blogDTO.setAuthor("焦前进"); List<Blog> blogs = mapper.queryBlogIf(blogDTO); System.out.println(blogs); session.close(); } ``` **测试结果** #### **1. 如果author为空,只根据title去查**  #### **2. 如果Title为空,只根据auther去查**  **“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。** ## **四、Set语句** ****需求:根据博客ID修改博客,如果博客作者为空,则修改博客标题,如果博客标题为空,则修改博客作者**** ### **1. 编写修改接口** ``` /** *功能描述: 修改博客 * @param blogDTO 修改信息 * @return int * @author jiaoqianjin * @date 2021/3/9 */ int updateBlog(BlogDTO blogDTO); ``` ### **2. 编写xml** ``` <!--注意set是用的逗号隔开--> <update id="updateBlog" parameterType="blogDTO"> update blog <set> <if test="title != null"> title = #{title}, </if> <if test="author != null"> author = #{author} </if> </set> where id = #{id}; </update> ``` ### **3. 测试** ``` @Test public void testUpdateBlog() { SqlSession session = MybatisUtil.getSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); BlogDTO blogDTO = new BlogDTO(); blogDTO.setTitle("Mybatis真难啊"); // blogDTO.setAuthor("焦前进"); blogDTO.setId(1); mapper.updateBlog(blogDTO); session.close(); } ``` #### **1. auther为空,修改title**  ##### **2. title为空,修改auther**  ## **五、SQL片段** **有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。提高可用性** ****声明一个SQL片段**** ``` <sql id="if-title-author"> <if test="title != null"> title = #{title}, </if> <if test="author != null"> author = #{author} </if> </sql> ``` ****引用SQL片段**** ``` <!--注意set是用的逗号隔开--> <update id="updateBlog" parameterType="blogDTO"> update blog <set> <include refid="if-title-author"></include> <!-- 在这里还可以引用其他的 sql 片段 --> </set> where id = #{id}; </update> ``` ****①最好基于 单表来定义 sql 片段,提高片段的可重用性**** ****②在 sql 片段中不要包括 where**** ## **六、Foreach语句** ****需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息**** ### **1. 编写接口** ``` /** *功能描述: 查询多个id的博客 * @param list 参数集合 * @return java.util.List<com.shida.entity.Blog> * @author jiaoqianjin * @date 2021/3/9 */ List<Blog> queryBlogForeach(List<Integer> list); ``` ### **2. 编写xml** ``` <select id="queryBlogForeach" parameterType="list" resultType="blog"> select * from blog <where> <!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog where 1=1 and (id=1 or id=2 or id=3) --> <foreach collection="list" item="id" open="and (" close=")" separator="or"> id=#{id} </foreach> </where> </select> ``` ### **3. 测试** ``` @Test public void testQueryBlogForeach(){ SqlSession session = MybatisUtil.getSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); List<Blog> blogs = mapper.queryBlogForeach(list); System.out.println(blogs); session.close(); } ``` ## **七、总结** **其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧。** Last modification:June 3rd, 2021 at 10:24 am © 允许规范转载