mybatis一级缓存

介绍

MyBatis连接数据库时,会创建 SqlSession对象,在 SqlSession 对象中有一个简单的缓存(由Map实现),将每次查询到的结果缓存起来

再次查询时,如果是同一个 sql,就从缓存中直接将结果取出

特点

  • 默认开启一级缓存

  • 必须是同一个SqlSession

  • 调用了 sqlSession.close() 方法,关闭数据库连接,同时释放一级缓存

  • 再次执行同一个sql,不想从缓存中提取,需要在查询前执行 sqlSession.clearCache();,清空缓存

  • 当 sqlSession 执行 insertsql语句、deletesql语句、updatesql语句、或者执行commit()方法时,会清空一级缓存

测试一级缓存

@Test
public void testSelect() throws IOException {

    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    IPostMapper mapper = sqlSession.getMapper(IPostMapper.class);

    //执行第一次查询
    List<PostUser> list=mapper.query();
    //执行第二次查询
    list=mapper.query();
    for(PostUser p:list) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm");
        String createTime=sdf.format(p.getCreateTime());
        String info = String.format("id:%s,标题:%s,用户名:%s,创建时间:%s", p.getId(), p.getTitle(), p.getUsername(),createTime);
        System.out.println(info);
    }
    sqlSession.close();
    inputStream.close();
}

在控制台中只显示一条sql语句,说明第二次查询,没有执行sql,而是从缓存中提取的

DEBUG [main] - ==>  Preparing: select p.id,p.title,p.create_time,p.user_id,u.username from user u,post p where u.id=p.user_id 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 3

测试清空缓存

@Test
public void testSelect() throws IOException {

    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    IPostMapper mapper = sqlSession.getMapper(IPostMapper.class);

    //执行第一次查询
    List<PostUser> list=mapper.query();
    //清空缓存
    sqlSession.clearCache();
    //执行第二次查询
    list=mapper.query();
    for(PostUser p:list) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm");
        String createTime=sdf.format(p.getCreateTime());
        String info = String.format("id:%s,标题:%s,用户名:%s,创建时间:%s", p.getId(), p.getTitle(), p.getUsername(),createTime);
        System.out.println(info);
    }
    sqlSession.close();
    inputStream.close();
}

清空缓存后,再次执行相同的sql,会再次查询数据库,在控制台中也能看到,打印2条sql

DEBUG [main] - ==>  Preparing: select p.id,p.title,p.create_time,p.user_id,u.username from user u,post p where u.id=p.user_id 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 3
DEBUG [main] - ==>  Preparing: select p.id,p.title,p.create_time,p.user_id,u.username from user u,post p where u.id=p.user_id 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 3

增删改 会清空缓存

@Test
public void testSelectById() throws IOException {

    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);

    User u=mapper.selectById("10001");
    String info = String.format("id:%s,用户名:%s,密码:%s", u.getId(), u.getUsername(), u.getPassword());
    System.out.println(info);

    User user=new User();
    user.setId("1000");
    user.setUsername("admin2");
    user.setPassword("12345678");
    int num=mapper.updateById(user);
    System.out.println("更新 "+num+" 条记录");

    u=mapper.selectById("10001");
    info = String.format("id:%s,用户名:%s,密码:%s", u.getId(), u.getUsername(), u.getPassword());
    System.out.println(info);


    sqlSession.close();
    inputStream.close();
}

控制台打印如下:

在控制台中打印2条相同的查询语句,说明执行 update 语句后,再次执行相同的查询sql时,会再次查询数据库


原文出处:/show_1IXOFtjgXL.html