正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持
1.一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。Session.clearCache()
2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
一级缓存
现在进行一级缓存的测试
package sdibt.lxj.test;
import org.apache.ibatis.session.SqlSession;
import sdibt.lxj.dao.IBookDao;
import sdibt.lxj.util.MybatisUtils;
public class TestMybatisCache {
public static void main(String[] args) throws ClassNotFoundException {
SqlSession session = MybatisUtils.getSession();
IBookDao dao = session.getMapper(IBookDao.class);
//发出两条查询语句
System.out.println("进行第一次查询");
dao.all();
System.out.println("进行第二次查询");
dao.all();
}
}
测试结果,很明显,在进行第二次查询的时候已经将该查询缓存了起来,不再执行sql,也就是说Mybatis默认是开启一级缓存的,不过必须是同一个session才有效
2018-07-08 15:50:42 [ main:0 ] - [ INFO ] {dataSource-1} inited
2018-07-08 15:50:42 [ main:54 ] - [ DEBUG ] Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
进行第一次查询
2018-07-08 15:50:42 [ main:80 ] - [ DEBUG ] Opening JDBC Connection
2018-07-08 15:50:42 [ main:82 ] - [ DEBUG ] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9a7504c]
2018-07-08 15:50:42 [ main:90 ] - [ DEBUG ] ==> Preparing: select * from book
2018-07-08 15:50:42 [ main:139 ] - [ DEBUG ] ==> Parameters:
2018-07-08 15:50:42 [ main:165 ] - [ DEBUG ] <== Total: 7
进行第二次查询
在查询完一次加上session.clearCache();就把session内的缓存清空了
System.out.println("进行第一次查询");
dao.all();
session.clearCache();
System.out.println("进行第二次查询");
dao.all();
在测试一下如果对表内的数据进行修改的话,缓存的查询会不会存在
//发出两条查询语句
System.out.println("进行第一次查询");
dao.all();
//删除一条记录
dao.delete1(7);
System.out.println("进行第二次查询");
dao.all();
看来对表进行修改会破坏一级缓存
2018-07-08 15:57:06 [ main:0 ] - [ INFO ] {dataSource-1} inited
2018-07-08 15:57:06 [ main:53 ] - [ DEBUG ] Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
进行第一次查询
2018-07-08 15:57:06 [ main:79 ] - [ DEBUG ] Opening JDBC Connection
2018-07-08 15:57:06 [ main:83 ] - [ DEBUG ] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9a7504c]
2018-07-08 15:57:06 [ main:90 ] - [ DEBUG ] ==> Preparing: select * from book
2018-07-08 15:57:06 [ main:137 ] - [ DEBUG ] ==> Parameters:
2018-07-08 15:57:06 [ main:163 ] - [ DEBUG ] <== Total: 7
2018-07-08 15:57:06 [ main:164 ] - [ DEBUG ] ==> Preparing: delete from book where id=?
2018-07-08 15:57:06 [ main:165 ] - [ DEBUG ] ==> Parameters: 7(Integer)
2018-07-08 15:57:06 [ main:168 ] - [ DEBUG ] <== Updates: 1
进行第二次查询
2018-07-08 15:57:06 [ main:168 ] - [ DEBUG ] ==> Preparing: select * from book
2018-07-08 15:57:06 [ main:168 ] - [ DEBUG ] ==> Parameters:
2018-07-08 15:57:06 [ main:171 ] - [ DEBUG ] <== Total: 6
二级缓存
mybatis使用二级缓存的话只需要在mapper标签里面加一个<cache/>
测试二级缓存,二级缓存是跨session的,如果使用二级缓存,则必须要提交事务
package sdibt.lxj.test;
import org.apache.ibatis.session.SqlSession;
import sdibt.lxj.dao.IBookDao;
import sdibt.lxj.util.MybatisUtils;
public class TestMybatisCache {
public static void main(String[] args) throws ClassNotFoundException {
//创建两个session
SqlSession session = MybatisUtils.getSession();
SqlSession session1 = MybatisUtils.getSession();
IBookDao dao = session.getMapper(IBookDao.class);
IBookDao dao1 = session1.getMapper(IBookDao.class);
dao.all();
//提交事务
session.commit();
dao1.all();
session1.commit();
}
}
2018-07-08 17:31:21 [ main:0 ] - [ INFO ] {dataSource-1} inited
2018-07-08 17:31:21 [ main:40 ] - [ DEBUG ] Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
2018-07-08 17:31:21 [ main:101 ] - [ DEBUG ] Cache Hit Ratio [sdibt.lxj.dao.IBookDao]: 0.0
2018-07-08 17:31:21 [ main:108 ] - [ DEBUG ] Opening JDBC Connection
2018-07-08 17:31:21 [ main:111 ] - [ DEBUG ] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4923ab24]
2018-07-08 17:31:21 [ main:120 ] - [ DEBUG ] ==> Preparing: select * from book
2018-07-08 17:31:21 [ main:166 ] - [ DEBUG ] ==> Parameters:
2018-07-08 17:31:21 [ main:197 ] - [ DEBUG ] <== Total: 7
2018-07-08 17:31:21 [ main:265 ] - [ DEBUG ] Cache Hit Ratio [sdibt.lxj.dao.IBookDao]: 0.5
实验,当某一个session对数据库进行了修改,其他session共享的二级缓存是否失效
package sdibt.lxj.test;
import org.apache.ibatis.session.SqlSession;
import sdibt.lxj.dao.IBookDao;
import sdibt.lxj.util.MybatisUtils;
public class TestMybatisCache {
public static void main(String[] args) throws ClassNotFoundException {
//创建两个session
SqlSession session = MybatisUtils.getSession();
SqlSession session1 = MybatisUtils.getSession();
SqlSession session2 = MybatisUtils.getSession();
IBookDao dao = session.getMapper(IBookDao.class);
IBookDao dao1 = session1.getMapper(IBookDao.class);
IBookDao dao2 = session2.getMapper(IBookDao.class);
dao.all();
//提交事务
session.commit();
dao2.delete1(1);
session.commit();
dao1.all();
session1.commit();
}
}
可以看到,在某一个 session执行了修改数据库的方法,仍然能命中缓存,说明二级缓存是不再session中的,所以如果要使用二级缓存,应该是一些不经常更新的数据
2018-07-08 17:35:17 [ main:0 ] - [ INFO ] {dataSource-1} inited
2018-07-08 17:35:17 [ main:38 ] - [ DEBUG ] Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
2018-07-08 17:35:18 [ main:100 ] - [ DEBUG ] Cache Hit Ratio [sdibt.lxj.dao.IBookDao]: 0.0
2018-07-08 17:35:18 [ main:106 ] - [ DEBUG ] Opening JDBC Connection
2018-07-08 17:35:18 [ main:110 ] - [ DEBUG ] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4923ab24]
2018-07-08 17:35:18 [ main:119 ] - [ DEBUG ] ==> Preparing: select * from book
2018-07-08 17:35:18 [ main:163 ] - [ DEBUG ] ==> Parameters:
2018-07-08 17:35:18 [ main:194 ] - [ DEBUG ] <== Total: 7
2018-07-08 17:35:18 [ main:207 ] - [ DEBUG ] Opening JDBC Connection
2018-07-08 17:35:18 [ main:207 ] - [ DEBUG ] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@710726a3]
2018-07-08 17:35:18 [ main:209 ] - [ DEBUG ] ==> Preparing: delete from book where id=?
2018-07-08 17:35:18 [ main:209 ] - [ DEBUG ] ==> Parameters: 1(Integer)
2018-07-08 17:35:18 [ main:210 ] - [ DEBUG ] <== Updates: 0
2018-07-08 17:35:18 [ main:213 ] - [ DEBUG ] Cache Hit Ratio [sdibt.lxj.dao.IBookDao]: 0.5