一级缓存
配置测试
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"