阅读 222

MyBatis之动态SQL的使用(mybatis动态sql是做什么的,都有哪些动态sql)

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。 主要有

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

数据库准备,创建一个blok的表

create table blog( id int primary key comment '博客id', title varchar(100) not null comment '博客标题', author varchar(30) not null comment '博客作者', create_time varchar(50) not null comment '创建时间', views int(30) not null comment '浏览量' )  insert into blog values(1,'javaWeb教程','黑马程序员',now(),1000)  insert into blog values(2,'安卓软件开发','周世凯,陈小龙',now(),1000)  insert into blog values(3,'数据结构','清华大学出版社',now(),10000)  insert into blog values(4,'人文基础与应用','毛灿月',now(),560) insert into blog values(5,'java教程','小钱',now(),123456) insert into blog values(6,'C语言','谭浩强',now(),10000) insert into blog values(7,'C语言','小毛',now(),10000) 复制代码

image.png

编写实体类

@Data public class Blog {     private int id;     private String title;     private String author;     private String  create_Time;     private int views; } 复制代码

1、if语句

编写接口

//    通过if,查询博客     List<Blog> queryBlogIF(Map map); 复制代码

编写Mapper.xml的sql语句

    <select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">         select * from blog         <where>             <if test="title!=null">                and title=#{title}             </if>             <if test="author!=null">                 and author=#{author}             </if>         </where>     </select> 复制代码

如果不传入 “title”,那么所有的 Blog 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行查找并返回对应的 Blog结果

where标签会在下面介绍

测试类

    @Test     public void queryBlogIF(){         SqlSession sqlSession = Mybatisutil.getSqlSession();         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);         HashMap map = new HashMap();         map.put("title","C语言");         map.put("author","谭浩强");         List<Blog> blogs = mapper.queryBlogIF(map);         for (Blog blog : blogs) {             System.out.println(blog);         }         sqlSession.close();     } 复制代码

结果

在这里插入图片描述

2、choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

编写接口

   //    通过choose,查询博客     List<Blog> queryBlogChoose(Map map); 复制代码

编写Mapper.xml的sql语句

   <select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog">         select * from blog         <where>             <choose>                 <when test="title!=null">                     title=#{title}                 </when>                 <when test="author!=null">                     and author=#{author}                 </when>                 <otherwise>                     and views=#{views}                 </otherwise>             </choose>         </where>     </select> 复制代码

测试类

    //通过choose查询     @Test     public void queryBlogChoose(){         SqlSession sqlSession = Mybatisutil.getSqlSession();         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);         HashMap map = new HashMap();         map.put("title","C语言");         map.put("author","谭浩强");         List<Blog> blogs = mapper.queryBlogChoose(map);         for (Blog blog : blogs) {             System.out.println(blog);         }         sqlSession.close();     } 复制代码

结果 在这里插入图片描述

当title满足要求时,即’break‘退出choose选择,就不会执行下面sql语句的拼接,和switch一样,所以这里查出来的有两条记录,当我只传入views参数时候,就会拼接 otherwise标签的语句,结果如下

image.png

3、trim、where、set

在我们拼接语句的时候,会有标点符号,前缀后缀符号等问题,这个时候可以用trim来解决。

如下面的sql语句,假如没有使用where标签,那么如果if语句中没有满足条件的拼接语句,这个时候我们的sql语句就是select * from blog where,这样的sql语句就是错误的,那么where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

    <select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">         select * from blog         where             <if test="title!=null">                and title=#{title}             </if>             <if test="author!=null">                 and author=#{author}             </if>     </select> 复制代码

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">   ... </trim> 复制代码

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">   update Author     <set>       <if test="username != null">username=#{username},</if>       <if test="password != null">password=#{password},</if>       <if test="email != null">email=#{email},</if>       <if test="bio != null">bio=#{bio}</if>     </set>   where id=#{id} </update> 复制代码

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

来看看与 set 元素等价的自定义 trim 元素吧:

<trim prefix="SET" suffixOverrides=",">   ... </trim> 复制代码

3.1、set修改数据

编写接口

    //使用set修改数据     int updateBlog(Map map); 复制代码

编写Mapper.xml的sql语句

<update id="updateBlog" parameterType="map">         update blog         <set>             <if test="title!=null">                  title=#{title},             </if>             <if test="author!=null">                 author=#{author}             </if>         </set>         where id=#{id}     </update> 复制代码

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

测试类

    @Test     public void updateBlog(){         SqlSession sqlSession = Mybatisutil.getSqlSession();         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);         HashMap map = new HashMap();         //map.put("title","C语言");         map.put("author","小浩强");         map.put("id",6);         mapper.updateBlog(map);         sqlSession.close();     } 复制代码

结果

image.png

4、Foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历

编写接口

  //使用foreach查询3 4 5 条博客     List<Blog> queryBlogForeach(Map map); 复制代码

编写Mapper.xml的sql语句

    <select id="queryBlogForeach" parameterType="map" resultType="pojo.Blog">         select * from blog         <where>             <foreach collection="ids" item="id" open="and (" close=")" separator="or">                 id=#{id}             </foreach>         </where>     </select> 复制代码

测试类

    @Test     public void queryBlogForeach(){         SqlSession sqlSession = Mybatisutil.getSqlSession();         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);         HashMap map = new HashMap();         ArrayList<Integer> idlist = new ArrayList<>();         idlist.add(3);         idlist.add(4);         idlist.add(5);         map.put("idlist",idlist);         List<Blog> blogs = mapper.queryBlogForeach(map);         for (Blog blog : blogs) {             System.out.println(blog);         }         sqlSession.close();     } 复制代码

结果:

在这里插入图片描述

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

5、SQL片段

我们会将公共的部分提取出来,方便复用

使用:

  1. 使用SQL标签提取公共的部分

<!--    将公共部分,需要重复使用的sql提取出来,使用sql标签--> <sql id="if-titlt-author">         <if test="title!=null">             title=#{title},         </if>         <if test="author!=null">             and author=#{author}         </if>     </sql> 复制代码

  1. 在需要使用的地方使用include标签

<!--    在需要使用的地方使用include标签-->     <select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">         select * from blog         <where>             <include refid="if-titlt-author"></include>         </where>     </select> 复制代码

注意事项:

  • 最好基于单表来定义SQL片段

  • 不要存在where标签

总结:

  • 动态SQl就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列就行

  • 书写sql语句之前先在sql查询环境中测试一下,避免写错,在编写Mappre.xml的时候找BUG。


作者:浪漫主义码农
链接:https://juejin.cn/post/7030747839223300132

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐