• 中文
    • English
  • 注册
  • 赞助本站

    • 支付宝
    • 微信
    • QQ

    感谢一直支持本站的所有人!

    • 查看作者
    • Mybatis:缓存

      一. 一级缓存

      这里以《Mybatis:动态SQL》一文中的Book的相关数据为例,演示一下一级缓存:

      测试类:

      package io.zhangjia.util;
      
      import com.alibaba.fastjson.JSON;
      import io.zhangjia.entity.Address;
      import io.zhangjia.entity.Order;
      import io.zhangjia.entity.Product;
      import io.zhangjia.mapper.BookMapper;
      import io.zhangjia.mapper.OrderMapper;
      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;
      import java.util.List;
      
      public class Main {
          public static void main(String[] args) throws IOException {
              String resource = "mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
              SqlSession sqlSession = build.openSession(true);
              BookMapper mapper = sqlSession.getMapper(BookMapper.class);
      
      //        第一次查询
              long start = System.currentTimeMillis();
              mapper.queryById(1);
              long end = System.currentTimeMillis();
              System.out.println("第一次查询耗时" + (end - start) + "毫秒");
              System.out.println("-------------------分隔线-------------------");
              //        第二次查询
              start = System.currentTimeMillis();
              mapper.queryById(1);
              end = System.currentTimeMillis();
              System.out.println("第二次查询耗时" + (end - start) + "毫秒");
      
      
              sqlSession.close();
              inputStream.close();
          }
      }

      通过下图的日志我们可以看到,虽然测试类执行了两次查询操作,但是却只有第一次查询执行了sql语句,这便是Mybatis的一级缓存机制。

      Mybatis:缓存

      Mybatis的一级缓存默认开启,作用于sqLSession,同一个sql Session连续查询同一条数据,只有第一次会发起SELECT查询,但是如果在两次查询中间有发生数据更新(增删改)操作,则会清空缓存:

      public class Main {
          public static void main(String[] args) throws IOException {
              String resource = "mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
              SqlSession sqlSession = build.openSession(true);
              BookMapper mapper = sqlSession.getMapper(BookMapper.class);
      
      //        第一次查询
              Book book = mapper.queryById(1);
      
              System.out.println("-------------------分隔线-------------------");
              
              
              book.setBookPrice(10.1);
              mapper.doUpdate(book); //更新数据
      
      //        第二次查询
              mapper.queryById(1);
      
      
              sqlSession.close();
              inputStream.close();
          }
      }

      Mybatis:缓存

      可以看到,因为两次查询中间执行了更新操作,所以即使查询的是同一条数据,依旧执行了两次sql语句。

      二.  二级缓存

      在上一节我们说过,Mybatis的一级缓存默认开启,并且作用于sqLSession,我们可以通过下面的例子来验证上述结论:

      package io.zhangjia.util;
      
      import com.alibaba.fastjson.JSON;
      import io.zhangjia.entity.Address;
      import io.zhangjia.entity.Book;
      import io.zhangjia.entity.Order;
      import io.zhangjia.entity.Product;
      import io.zhangjia.mapper.BookMapper;
      import io.zhangjia.mapper.OrderMapper;
      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;
      import java.util.List;
      
      public class Main {
          public static void main(String[] args) throws IOException {
              String resource = "mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
              SqlSession sqlSession = build.openSession(true);
              BookMapper mapper = sqlSession.getMapper(BookMapper.class);
      
      //        第一次查询
              Book book = mapper.queryById(1);
      
              sqlSession.close();
      
              System.out.println("-------------------分隔线-------------------");
      
              SqlSession sqlSession2 = build.openSession(true);
              BookMapper mapper2 = sqlSession2.getMapper(BookMapper.class);
      
      //        第二次查询
              mapper2.queryById(1);
      
      
              sqlSession2.close();
              inputStream.close();
          }
      }

      在上面的测试类中,我们的两次查询操作分别使用了不同的sqlSession,可以看到,因为一级缓存作用于sqLSession,所以即使两次查询的是同一条数据,但是仍然会执行两次查询语句:

      Mybatis:缓存

      我们可以通过开启Mybatis的二级缓存来解决这个问题。要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/>即可:

      Mybatis:缓存

      除了修改SQL映射文件,还需要将Book的实体类实现Serializable接口

      public class Book implements Serializable {
         ......
      }

      Mybatis二级缓存作用于SessionFactory,如果两次查询基于同一个SessionFactory,那么就从二级缓存中取数据,而不用到数据库里去取了,我们上面的sqlSession1和sqlSession2都是基于同一个SessionFactory创建的,所以开启二级缓存后,两次查询即使使用不同的sqlSession也只会执行一次SQL语句。

      Mybatis:缓存

      最后我们可以在Mapper.xml中,为select标签添加useCache属性来决定该查询是否使用缓存

      <select useCache=='false' id="queryByAddressId" parameterType="int"resultType="address">
      SELECT * FROM address WHERE address_id=#{addressId}
      </select>

      参考资料

      how2j

    • 0
    • 0
    • 0
    • 417
    • 请登录之后再进行评论

      登录
    • 做任务
    • 实时动态
    • 偏好设置
    • 返回顶部
    • 单栏布局 侧栏位置: