• 中文
    • English
  • 注册
  • 查看作者
  • 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
  • 1.4k
  • 请登录之后再进行评论

    登录
    单栏布局 侧栏位置: