zoukankan      html  css  js  c++  java
  • 8.Mybatis的动态SQL

    转载:https://blog.kuangstudy.com/index.php/archives/506/

    一.动态SQL

    1.介绍

    什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

    官网说明:

     1 官网描述:
     2     MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
     3     虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
     4     动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
     5     
     6     -------------------------------
     7     - if
     8     - choose (when, otherwise)
     9     - trim (where, set)
    10     - foreach
    11     -------------------------------
    • 我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。

    • 那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

    2.搭建环境

    (1)新建一个数据库表:blog

    1 CREATE TABLE `blog` (
    2   `id` varchar(50) NOT NULL COMMENT '博客id',
    3   `title` varchar(100) NOT NULL COMMENT '博客标题',
    4   `author` varchar(30) NOT NULL COMMENT '博客作者',
    5   `create_time` datetime NOT NULL COMMENT '创建时间',
    6   `views` int(30) NOT NULL COMMENT '浏览量'
    7 ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    (2)建立基础工程

    • 导包

    • 编写核心配置文件

    • 编写实体类

    • 编写Mapper接口文件和Mapper.xml文件

    (2.1)添加工具类IDUtils.java:

     1 import org.junit.Test;
     2 
     3 import java.util.UUID;
     4 
     5 public class IDUtils {
     6 
     7     public static String getId(){
     8         return UUID.randomUUID().toString().replaceAll("-","");
     9     }
    10 
    11     @Test
    12     public void test(){
    13         System.out.println(IDUtils.getId());
    14         System.out.println(IDUtils.getId());
    15         System.out.println(IDUtils.getId());
    16     }
    17 }

    (2.2)添加实体类Blog.java:

     1 import lombok.Data;
     2 
     3 import java.util.Date;
     4 
     5 @Data
     6 public class Blog {
     7 
     8     private String id;
     9     private String title;
    10     private String author;
    11     private Date createTime; //属性名和数据库字段名不一致,数据库字段名为create_time 需要开启驼峰命名转换
    12     private int views;
    13 }

    (2.3)添加接口文件BlogMapper.java:

    1 import edu.ustc.wzh.pojo.Blog;
    2 
    3 public interface BlogMapper {
    4 
    5     //插入数据
    6     int addBlog(Blog blog);
    7 }

    (2.4)添加BlogMapper.xml:

     1 <!--namespace用于绑定一个对应的Dao/Mapper接口-->
     2 <mapper namespace="edu.ustc.wzh.dao.BlogMapper">
     3 
     4     <insert id="addBlog" parameterType="Blog">
     5         insert into mybatis.blog(id, title, author, create_time, views)
     6         value (#{id},#{title},#{author},#{createTime},#{views});
     7     </insert>
     8 
     9 
    10 </mapper>

    (2.5)测试代码:

     1 @Test
     2 public void addInitBlog(){
     3     SqlSession session = MybatisUtils.getSession();
     4     BlogMapper mapper = session.getMapper(BlogMapper.class);
     5 
     6     Blog blog = new Blog();
     7     blog.setId(IDUtils.getId());
     8     blog.setTitle("Mybatis如此简单");
     9     blog.setAuthor("狂神说");
    10     blog.setCreateTime(new Date());
    11     blog.setViews(9999);
    12 
    13     mapper.addBlog(blog);
    14 
    15     blog.setId(IDUtils.getId());
    16     blog.setTitle("Java如此简单");
    17     mapper.addBlog(blog);
    18 
    19     blog.setId(IDUtils.getId());
    20     blog.setTitle("Spring如此简单");
    21     mapper.addBlog(blog);
    22 
    23     blog.setId(IDUtils.getId());
    24     blog.setTitle("微服务如此简单");
    25     mapper.addBlog(blog);
    26 
    27     session.close();
    28 }

    3.动态SQL之IF语句

    (3.1)IF标签:

    • 需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询,都为空则查询全部博客

    BlogMapper.java:

    1 //根据传入的属性查询博客(例如传入作者就查作者,传入title就查title)
    2 List<Blog> queryBlogIF(Map map);

    BlogMapper.xml:

    1 <select id="queryBlogIF" parameterType="map" resultType="blog">
    2     select * from mybatis.blog where 1=1
    3     <if test="title != null">
    4         and title = #{title}
    5     </if>
    6     <if test="author != null">
    7         and author = #{author}
    8     </if>
    9 </select>

    测试代码:

     1 @Test
     2 public void queryBlogIFTest(){
     3     SqlSession session = MybatisUtils.getSession();
     4     BlogMapper mapper = session.getMapper(BlogMapper.class);
     5 
     6 
     7     Map<String,String> map = new HashMap<String,String>();
     8     map.put("title","Mybatis如此简单");
     9 
    10     List<Blog> blogs = mapper.queryBlogIF(map);
    11 
    12     for (Blog blog : blogs) {
    13 
    14         System.out.println(blog);
    15     }
    16 
    17     session.close();
    18 }

    (3.2)where标签:

    • 这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。

    修改BlogMapper.xml:将 where 1=1 替换成了where标签

     1 <select id="queryBlogIF" parameterType="map" resultType="blog">
     2     select * from mybatis.blog
     3     <where>
     4         <if test="title != null">
     5             and title = #{title}
     6         </if>
     7         <if test="author != null">
     8             and author = #{author}
     9         </if>
    10     </where>
    11 </select>

    (3.3)choose(when,otherwise)标签:(类似于Java中的switch case default)

    • 如果一个都不满足查询结果为空

    • 满足了第一个when执行后就退出,不会再执行后面的when或otherwise

    BlogMapper.java:

    1 List<Blog> queryBlogChoose(Map map);

    BlogMapper.xml:

     1 <select id="queryBlogChoose" parameterType="map" resultType="blog">
     2     select * from mybatis.blog
     3     <where>
     4         <choose>
     5             <when test="title != null">
     6                 title = #{title}
     7             </when>
     8             <when test="author != null">
     9                 and author = #{author}
    10             </when>
    11             <otherwise>
    12                 and views = #{views}
    13             </otherwise>
    14         </choose>
    15     </where>
    16 </select>

    测试代码:

     1 @Test
     2 public void queryBlogChooseTest(){
     3     SqlSession session = MybatisUtils.getSession();
     4     BlogMapper mapper = session.getMapper(BlogMapper.class);
     5 
     6 
     7     Map<String,String> map = new HashMap<String,String>();
     8     map.put("title","Mybatis如此简单");
     9 
    10     List<Blog> blogs = mapper.queryBlogChoose(map);
    11 
    12     for (Blog blog : blogs) {
    13 
    14         System.out.println(blog);
    15     }
    16 
    17     session.close();
    18 }

    (3.4)set标签:一般和upate语句使用,删除多余逗号

    • 这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(译者注:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)

    BlogMapper.java:

    1 int updateBlogSet(Map map);

    BlogMapper.xml:

     1 <update id="updateBlogSet" parameterType="map">
     2     update mybatis.blog
     3     <set>
     4         <if test="title != null">
     5             title = #{title},
     6         </if>
     7         <if test="author != null">
     8             author = #{author}
     9         </if>
    10     </set>
    11     where id = #{id}
    12 </update>

    测试代码:

     1 @Test
     2 public void updateBlogSetTest(){
     3     SqlSession session = MybatisUtils.getSession();
     4     BlogMapper mapper = session.getMapper(BlogMapper.class);
     5 
     6 
     7     Map<String,String> map = new HashMap<String,String>();
     8     map.put("title","我学习Mybatis如此简单");
     9     map.put("id","5a95b31cb1494aa68c498c5c54243439");
    10 
    11     int res = mapper.updateBlogSet(map);
    12 
    13     if (res > 0){
    14         System.out.println("更新成功!");
    15     }
    16 
    17     session.close();
    18 }

    (3.5)trim标签:用来定制自定义的格式

    • <trim prefix="" prefixOverrides="" suffix="" suffixOverrides=""></trim>
    • prefix:前置标签

    • prefixOverrides:忽略的前置符号

    • suffix:后置标签

    • suffixOverrides:忽略的后置符号

    例子:

    where标签:前置标签为where时忽略掉开头and或or

    <trim prefix="WHERE" prefixOverrides="AND |OR ">
      ...
    </trim>

    set标签:前置标签为set时忽略掉结尾逗号

    <trim prefix="SET" suffixOverrides=",">
      ...
    </trim>

    (3.6)SQL片段

    • 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

    提取公共的SQL片段:

    1 <sql id="if-title-author">
    2     <if test="title != null">
    3         title = #{title}
    4     </if>
    5     <if test="author != null">
    6         and author = #{author}
    7     </if>
    8 </sql>

    引用SQL片段:

    1 <select id="queryBlogIF" parameterType="map" resultType="blog">
    2     select * from mybatis.blog
    3     <where>
    4         <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
    5         <include refid="if-title-author"></include>
    6         <!-- 在这里还可以引用其他的 sql 片段 -->
    7     </where>
    8 </select>

    注意:

    • 最好基于 单表来定义 sql 片段,提高片段的可重用性

    • 在 sql 片段中不要包括 where,set这种会优化SQL的语句,以防出错

    (3.7)Foreach标签

    • 动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。

    • 我们需要查询Blog表中的id=1或id=2或id=3的博客信息:

      select * from blog where 1=1 and (id=1 or id=2 or id=3)
    • 格式:

      1 collection:指定输入对象中的集合属性
      2 item:每次遍历生成的对象
      3 open:开始遍历时的拼接字符串
      4 close:结束时拼接的字符串
      5 separator:遍历对象之间需要拼接的字符串

    修改Blog表数据:

    BlogMapper.java:

    1 List<Blog> queryBlogForeach(Map map);

    BlogMapper.xml:

     1 <select id="queryBlogForeach" parameterType="map" resultType="blog">
     2     select * from blog
     3     <where>
     4         <!--
     5         collection:指定输入对象中的集合属性
     6         item:每次遍历生成的对象
     7         open:开始遍历时的拼接字符串
     8         close:结束时拼接的字符串
     9         separator:遍历对象之间需要拼接的字符串
    10         select * from blog where 1=1 and (id=1 or id=2 or id=3)
    11       -->
    12         <foreach collection="ids"  item="blogId" open="and (" close=")" separator="or">
    13             id=#{blogId}
    14         </foreach>
    15     </where>
    16 </select>

    测试代码: map.put("ids",ids); 此处的ids和 <foreach collection="ids" 一致

     1 @Test
     2     public void queryBlogForeachTest(){
     3         SqlSession session = MybatisUtils.getSession();
     4         BlogMapper mapper = session.getMapper(BlogMapper.class);
     5 
     6         HashMap map = new HashMap();
     7         List<Integer> ids = new ArrayList<Integer>();
     8         ids.add(1);
     9         ids.add(2);
    10         ids.add(3);
    11         map.put("ids",ids);
    12 
    13         List<Blog> blogs = mapper.queryBlogForeach(map);
    14 
    15         System.out.println(blogs);
    16 
    17         session.close();
    18     }
  • 相关阅读:
    学习第23天
    学习第22天
    学习第21天
    Servlet交互与JSP
    Cookie与Session
    servlet入门
    网络编程
    DOM4j
    xml文档对象模型doc
    反射
  • 原文地址:https://www.cnblogs.com/zhihaospace/p/12301873.html
Copyright © 2011-2022 走看看