Mybatis总结三(动态SQL、Mybatis缓存机制)

一、动态SQL

动态 SQL 是 MyBatis 的强大特性之一,可以根据不同条件拼接 SQL 语句。最好先写出完整的SQL语句,在按照动态SQL的标签规则等去进行排列组合。

  • if

      List<Blog> queryBlogIf(Map map);
    
        <select id="queryBlogIf" parameterType="map" resultType="blog">
            select *
            from mybatis.Blog
            <where>
                <if test="title != null">
                    and title = #{title}
                </if>
                <if test="author != null">
                    and author=#{author}
                </if>
            </where>
        </select>
    
      @Test
      public void queryBlogIf() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        // hashMap.put("title", "spring");
        hashMap.put("author", "olarian");
        List<Blog> blogs = mapper.queryBlogIf(hashMap);
        for (Blog blog : blogs) {
          System.out.println(blog);
        }
        sqlSession.close();
      }
    

    快捷实现了SQL的复用,避免繁琐的方法重载

  • choose (when, otherwise)

    把这看做switch-case-default

      List<Blog> queryBlogChoose(Map map);
    
        <select id="queryBlogChoose" parameterType="map" resultType="blog">
            select * from mybatis.blog
            <where>
                <choose>
                    <when test="title!=null">
                        title = #{title}
                    </when>
                    <when test="author!=null">
                        author = #{author}
                    </when>
                    <otherwise>
                        views=443
                    </otherwise>
                </choose>
            </where>
        </select>
    
      @Test
      public void queryBlogChoose() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("title", "mybatis");
        hashMap.put("author", "olarian");
        hashMap.put("views", 443);
        List<Blog> blogs = mapper.queryBlogChoose(hashMap);
        for (Blog blog : blogs) {
          System.out.println(blog);
        }
        sqlSession.close();
      }
    
  • trim (where, set)

    1. where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

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

        void updateBlog(Map map);
      
          <update id="updateBlog" parameterType="map">
              update mybatis.blog
              <set>
                  <if test="title!=null">
                      title=#{title},
                  </if>
                  <if test="author!=null">
                      author=#{author}
                  </if>
              </set>
              where id = #{id}
          </update>
      
        @Test
        public void updateBlog() {
          SqlSession sqlSession = MybatisUtils.getSqlSession();
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          HashMap hashMap = new HashMap();
          hashMap.put("title", "mybatis-plus");
          hashMap.put("author", "olarian");
          hashMap.put("id", "eea97146be2f46b3a5d4b5a2fd14336c");
          mapper.updateBlog(hashMap);
          sqlSession.close();
        }
      
    3. trim可以设置前后缀并进行覆盖

          <trim prefix="" prefixOverrides="" suffix="" suffixOverrides="">
                  
          </trim>
      

      where和set本质上是trim的特殊形式:

      <!--  where  -->
      <trim prefix="WHERE" prefixOverrides=" AND | OR ">
        ...
      </trim>
      <!--  set  -->
      <trim prefix="SET" suffixOverrides=",">
        ...
      </trim>
      
  • foreach

    动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

      List<Blog> queryBlogForeach(Map map);
    
        <select id="queryBlogForeach" parameterType="map" resultType="blog">
            select *
            from mybatis.blog
            <where>
                id in
                <foreach collection="ids" separator="," open="(" close=")" item="id">
                    #{id}
                </foreach>
            </where>
        </select>
    
      @Test
      public void queryBlogForeach() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        ArrayList<Integer> ids = new ArrayList<>();
        hashMap.put("ids", ids);
        ids.add(1);
        ids.add(2);
        List<Blog> blogs = mapper.queryBlogForeach(hashMap);
        for (Blog blog : blogs) {
          System.out.println(blog);
        }
        sqlSession.close();
      }
    
  • SQL片段

    设置常用SQL,便于复用

        <sql id="sql01">
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author=#{author}
            </if>
        </sql>
    

    再使用<include refid=“sql01”>标签引用就行了!

    注意事项:

    1. 最好基于单表来定义SQL片段
    2. SQL片段中不要存在where标签

二、缓存

Q:什么是缓存?

A:缓存(Cache)本意是指可以进行高速数据交换的存储器,通俗点来说,就是通过将数据提前存放到内存,以提高访问速度

Q:什么时候使用缓存?

A:对于那些经常需要查询并且不经常改变的数据,可以使用缓存来增加读取速度。

Mybatis缓存机制:

  • 一级缓存

    默认情况下,只有一级缓存开启(SqlSession级别的缓存,也成为本地缓存),sqlsession.close()后缓存被清楚!

      @Test
      public void queryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("id", "1");
        Blog blog1 = mapper.queryBlogById(hashMap);
        Blog blog2 = mapper.queryBlogById(hashMap);
        System.out.println(blog1);
        System.out.println(blog2);
        System.out.println(blog1 == blog2);
        sqlSession.close();
      }
    // 在一个Session中查询两次相同记录,通过查看日志发现,只进行了一次查询,并且两次查询结果为true
    
    [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection
    [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1613095350.
    [com.ola.dao.BlogMapper.queryBlogById]-==>  Preparing: select * from mybatis.blog where id = ?;
    [com.ola.dao.BlogMapper.queryBlogById]-==> Parameters: 1(String)
    [com.ola.dao.BlogMapper.queryBlogById]-<==      Total: 1
    =============================================
    Blog(id=1, title=spring, author=olarian, createTime=Wed Jan 13 12:45:11 CST 2021, views=443)
    Blog(id=1, title=spring, author=olarian, createTime=Wed Jan 13 12:45:11 CST 2021, views=443)
    true
    [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6025e1b6]
    [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1613095350 to pool.
    
    进程已结束,退出代码0
    

    Q:什么时候缓存会失效?

    A:

    1. 查询不同记录

    2. 增删改操作(可能会改变原来数据的操作)

    3. 查询不同的Mapper

    4. 手动清理缓存

      sqlSession.clearCache();
      
  • 二级缓存(只要mapper还在,二级缓存就在,提升了缓存作用域)

    • 只有当一级缓存会话提交或者关闭的时候,二级缓存才会生效

    • 二级缓存需要手动开启和配置,是基于namespace级别的缓存(一个Mapper一个二级缓存)

    开启方式:

    1. 在mybatis-config.xml中的settings标签下显式配置开启全局缓存(默认也是开启的,但是最好显式的配置一下)

          <settings>
              <setting name="cacheEnabled" value="true"/>
          </settings>
      
    2. 在你的 SQL 映射文件中添加一行:

    <cache/>
    
    <!--
    这些属性可以通过 cache 元素的属性来修改。比如:
    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    	这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的	对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
    -->
    <!--
    可用的清除策略有:
    LRU – 最近最少使用:移除最长时间不被使用的对象。
    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
    WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
    默认的清除策略是 LRU。
    -->
    <!--
    flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
    size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
    readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
    -->
    <!--
    注意:二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。
    -->
    
  • 缓存原理

小狂神你是真猛啊

  • 自定义缓存ehcache

三、其他

  1. 以下给出一个从 mybatis-config.xml 文件创建 SqlSessionFactory 的示例:

    String resource = "org/mybatis/builder/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(inputStream);
    

    完整工具类:

    package com.ola.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * ClassName:MybatisUtils Package:com.ola.utils
     *
     * @author morningj
     * @date 2021/1/10 15:39
     */
    public class MybatisUtils {
      private static SqlSessionFactory sqlSessionFactory;
    
      static {
        try {
          String resource = "mybatis-config.xml";
          InputStream inputStream = Resources.getResourceAsStream(resource);
          sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    
      public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
      }
    }
    
  2. 注册mapper最好使用class注册,但是要注意类和xml配置要在同一个包下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值