MyBatis05缓存

一级缓存

配置测试

public class CacheTest {

    private InputStream in;
    private SqlSessionFactory factory;
    private IUserDao dao;
    private SqlSession sqlSession;



    @Before//用于在测试方法执行之前执行
    public void init() throws Exception {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    @After//用于在测试方法执行之后执行
    public void destroy() throws Exception {

        in.close();
    }

    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache() {
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IUserDao.class);
        User user1 = dao.findById(2);
        System.out.println("第一次查询:"+ user1);
        User user2 = dao.findById(2);
        System.out.println("第二次查询:"+ user2);
        System.out.println(user1 == user2);

        sqlSession.close();
    }

    @Test
    public void testFirstLevelCache2() {
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IUserDao.class);
        User user1 = dao.findById(2);
        System.out.println(user1);
        //清空缓存
        sqlSession.clearCache();
        dao = sqlSession.getMapper(IUserDao.class);
        User user2 = dao.findById(2);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }
}
testFirstLevelCache 执行结果
Opening JDBC Connection
Created connection 125994398.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
==>  Preparing: select * from user where id = ? 
==> Parameters: 2(Integer)
<==      Total: 1
第一次查询:blog.mybatist.domain.User@19b89d4
Cache Hit Ratio [blog.mybatis.dao.IUserDao]: 0.0
第二次查询:blog.mybatis.domain.User@19b89d4
true
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Returned connection 125994398 to pool.
第一次查询和第二次查询拿到的对象是同一个对象,且只发出了一次SQL查询语句
testFirstLevelCache2 执行结果
Opening JDBC Connection
Created connection 125994398.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
==>  Preparing: select * from user where id = ? 
==> Parameters: 2(Integer)
<==      Total: 1
blog.mybatis.domain.User@19b89d4
Cache Hit Ratio [blog.mybatis.dao.IUserDao]: 0.0
==>  Preparing: select * from user where id = ? 
==> Parameters: 2(Integer)
<==      Total: 1
blog.mybatis.domain.User@2415fc55
false
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Returned connection 125994398 to pool.
第一次查询和第二次查询拿到的是不同对象,且发出了两次SQL查询语句

分析总结

  • 一级缓存是SqlSession范围的缓存,当调用 SqlSession 的增删改,commit(),close(),clearCache() 等方法时,就会清空一级缓存
  • 第一次发出一个查询sql,sql查询结果写入 sqlSession 的一级缓存中,存放的是一个 Map,key用于标识sql,value用于存放信息
    第二次发起查询sql,先去找缓存中是否有信息,缓存中有,直接从缓存中获取信息。
    如果中间 sqlSession 去执行commit()(进行数据的增删改)或是主动使用clearCache(),就清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  • 一级缓存内容中存放的是一个对象
  • 不同 SqlSession 的缓存是不同的

二级缓存

配置测试

    <!-- 在配置文件中开启二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <!-- 在对应的映射文件中开启二级缓存-->
    <cache/>
//二级缓存测试
public class CacheTest {

    private InputStream in;
    private SqlSessionFactory factory;

    @Before//用于在测试方法执行之前执行
    public void init() throws Exception {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    @After//用于在测试方法执行之后执行
    public void destroy() throws Exception {

        in.close();
    }

    @Test
    public void testSecondLevelCache(){
        SqlSession sqlSession1 = factory.openSession();
        IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
        User user1 = dao1.findById(2);
        System.out.println(user1);
        sqlSession1.close();//一级缓存消失

        SqlSession sqlSession2 = factory.openSession();
        IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
        User user2 = dao2.findById(2);
        System.out.println(user2);
        sqlSession2.close();

        System.out.println(user1 == user2);
    }
}
testSecondLevelCache执行结果
Opening JDBC Connection
Created connection 125994398.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
==>  Preparing: select * from user where id = ? 
==> Parameters: 2(Integer)
<==      Total: 1
blog.mybatis.domain.User@19b89d4
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@782859e]
Returned connection 125994398 to pool.
Cache Hit Ratio [blog.mybatis.dao.IUserDao]: 0.5
blog.mybatis.domain.User@6736fa8d
false
进行两次查询,在第一次查询后将一级缓存关闭,再进行第二次查询,且第二次查询并没有发出SQL查询语句,此时数据来自二级缓存

分析总结

  • 二级缓存是Mapper级别的缓存,Mapper以命名空间为单位创建缓存数据结构,结构是Map。
  • 二级缓存并不是跟一级缓存一样存放对象,而是存放数据

缓存的一些注意事项

二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以实体类要实现 java.io.serializable 接口。
对于变化频率较高的SQL,需要禁用二级缓存:对应SQL查询语句中 <select> 标签中设置 useCache="false",默认 useCache="true"
posted @ 2020-07-28 10:41  飞天小海星  阅读(122)  评论(0)    收藏  举报