缓存概述
缓存主要用来提高查询的性能,减少跟数据库交互的次数,减轻数据库承受的压力。适用于读多写少的场景,如果数据变化频率非常高,则不适用。
MyBatis的缓存分为一级缓存和二级缓存
一级缓存特点
一级缓存默认级别是SqlSession级别的缓存,每个SqlSession缓存的数据不能共存,两次查询之间的更新操作(增删改)会刷新一级缓存。或者调用SqlSession的close方法时,此时一级缓存不存在。
具体测试:
- 两次查询数据库中的数据,存入user对象中,第二次查询将会从一级缓存中取出该对象。对比查询出来的对象的内存地址,输出结果为true,表示两次得到的对象是相同的,控制台输出也可以看出可以看出,第二次并未从数据库进行查询
//两次直接查询,第二次未进行数据库的查询
@Test
public void getUserByIdTest1() {
SqlSession sqlSession =null;
try {
sqlSession=SqlSessionFactoryUtils.openSqlSession();
// 获得mapper对象,用工具类直接调用静态方法获得SqlSession对象
IUserMapping userMapper = sqlSession.getMapper(IUserMapping.class);
System.out.println("第一次查询--------------------------------------------");
User user1 = userMapper.getUserById(3);
//以下的测试在此处增改
System.out.println("第二次查询--------------------------------------------");
User user2=userMapper.getUserById(3);
//两次输出结果
System.out.println(user1==user2);
} catch (Exception e) {
e.printStackTrace();
}finally {
//用完关闭
if(sqlSession!=null) {
sqlSession.close();
}
}
}
测试结果:
- 在两次查询过程中间修改user对象的username属性。对象中的username属性在缓存中被修改,所以第二次输出的是修改后的值,即是从一级缓存中获取的对象
System.out.println("第一次查询--------------------------------------------");
User user1 = userMapper.getUserById(3);
System.out.println("第一次查询:"+user1.getUsername());
//创建一个User对象,对User的属性进行修改
user1.setUsername("李四");
System.out.println("第二次查询------------------------------------------");
User user2=userMapper.getUserById(3);
System.out.println("第二次查询:"+user2.getUsername());
//两次输出结果
System.out.print("内存地址对比:");
System.out.println(user1==user2);
输出结果如下:
- 在两次查询的之间进行修改数据库信息的操作,可以从控制台输出看出,两次查询的结果是不一致的,第二次查询的结果不再是从缓存中获取,而是从数据库中再次进行查询,返回一个新的user对象
IUserMapping userMapper = sqlSession.getMapper(IUserMapping.class);
System.out.println("第一次查询--------------------------------------------");
User user1 = userMapper.getUserById(3);
System.out.println(user1.getUsername());
//修改用户名
User user = new User();
user.setId(3);
user.setUsername("小小鸟");
userMapper.update(user);
System.out.println("第二次查询--------------------------------------------");
User user2=userMapper.getUserById(3);
System.out.println(user2.getUsername());
//两次输出结果
System.out.print("内存地址对比:");
System.out.println(user1==user2);
sqlSession.commit();
- 增加第三次查询,在查询前关闭SqlSession,在第三次查询时是从数据库中查询。
System.out.println("第三次查询--------------------------------------------");
sqlSession.close();
sqlSession=SqlSessionFactoryUtils.openSqlSession();
// 获得mapper对象,用工具类直接调用静态方法获得SqlSession对象
userMapper = sqlSession.getMapper(IUserMapping.class);
User user3 = userMapper.getUserById(3);
System.out.print("第一次和第三次内存地址对比:");
System.out.println(user3==user1);
二级缓存
二级缓存是SqlSessionFactory级别的缓存:SqlSessionFactory工厂对象只有一个,所有的SqlSession对象共享同行一个SqlSessionFactory
- 开启起二级缓存(默认处于开始状态),在我们的mybatis-config.xml主配置文件中进行配置
<!-- 开启二级缓存 -->
<settings>
<setting name="cacheEnbaled" value="true"/>
</settings>
- 在映射器的xml文件中开启二级缓存
<!-- 开启二级缓存 -->
<cache></cache>
- 默认的二级缓存配置会有如下的特点:
- 所有的Select语句将会被缓存
- 所有的更新语句(insert、update、delete)将会刷新缓存
- 缓存将会采用LRU(LeastRecently Used 最近最少使用)
- 算法来回收,还有FIFO(先进先出)等其他算法,建议采用LRU
- 缓存会存储1024个对象的引用
代码验证:
@Test
public void getUserByIdTest4() {
SqlSession sqlSession =null;
try {
sqlSession=SqlSessionFactoryUtils.openSqlSession();
// 获得mapper对象,用工具类直接调用静态方法获得SqlSession对象
IUserMapping userMapper = sqlSession.getMapper(IUserMapping.class);
System.out.println("第一次查询--------------------------------------------");
User user1 = userMapper.getUserById(3);
System.out.println(user1.getUsername());
System.out.println("第二次查询--------------------------------------------");
User user2=userMapper.getUserById(3);
System.out.println(user2.getUsername());
System.out.println("第三次查询--------------------------------------------");
sqlSession.close();
sqlSession=SqlSessionFactoryUtils.openSqlSession();
// 获得mapper对象,用工具类直接调用静态方法获得SqlSession对象
userMapper = sqlSession.getMapper(IUserMapping.class);
User user3 = userMapper.getUserById(3);
User user4=userMapper.getUserById(3);
User user5=userMapper.getUserById(3);
System.out.println(user3);
System.out.println(user4);
System.out.println(user5);
} catch (Exception e) {
e.printStackTrace();
}finally {
//用完关闭
if(sqlSession!=null) {
sqlSession.close();
}
}
}
开启二级缓存,从控制台输出的结果,可以看出在关闭SqlSession后,数据仍旧是存在缓存中的(二级缓存),并没有向数据库查询数据。在关闭SqlSession后,以及缓存的数据是已经被清空,SqlSession会向上从二级缓存中查询数据,结尾处输出了user3、user4、user5三次获得的对象内存地址,可以看出,后续从缓存中取出的对象每次的内存地址都是不一样的。
Ehcahe缓存框架
EhCache是一个纯粹的Java进程内的缓存框架。
- 添加EhCache需要的jar包
- 引入EhCache配置文件
解压jsqlparser-0.9.5.jar可获得配置文件,配置文件和mybatis的住配置文件放一起(此处为mybatis-config.xml)
在配置ehcache-failsafe.xml配置文件中有相应配置信息,可按需进行修改,此处暂默认
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
- 配置MyBatis的二级缓存采用EhCache
在我们的映射器的配置文件中开启缓存
<!-- 开启Encache二级缓存 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>