缓存机制
1.缓存分类
同hibernate一样,mybatis分为两级缓存:
1.一级缓存:
属于SqlSession范围内的缓存,属性内存级别的缓存
(hibernate一级缓存,是Session范围内的缓存)
2.二级缓存
属于Mapper范围内的缓存,为同个mapper范围内的多个SqlSession共享的区域,但是Mybatis并没有对二级缓存提供实现,要依赖于第三方缓存厂商(EHCache,Redis…)
(hibernate二级缓存,为多个session共享,是SessionFactory级别的缓存)
2.一级缓存
Mybatis的一级缓存是自动开启的,无需手动管理.
一级缓存使用:
1.第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信
息。得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为
了让缓存中存储的是最新的信息,避免脏读。
2.第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户
信息。
<!--UserMapper.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.UserMapper">
<!--一级缓存-->
<select id="selectByCache1" resultType="User">
select * from User where id = #{id}
</select>
</mapper>
//接口
public interface UserMapper {
User selectByCache1(int id);
}
//Service
/**
* 一级缓存测试
* @return
*/
public User findByCache1(int id){
SqlSession session = DBUtil.openSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
//第一次取值(会从数据库中查找,并放入session缓存空间)
User user = mapper.selectByCache1(id);
//第二次取值(默认会从session取值,如果取不到,则再次请求数据库)
//如果进行增删改数据后,执行commit()操作,则缓存失效
//session.commit();
User user2 = mapper.selectByCache1(id);
System.out.println((user==user2)+"....................");
session.close();
return user;
}
通过上述代码,可以验证一级缓存的存在.
3.二级缓存
1.Mybatis并没有提供对二缓存的实现
2.使用第三个缓存时,要在Config文件中手动开启二级缓存
3.多个SqlSession共享二级缓存
4.二级缓存可以手动提供缓存空间的管理策略
二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是二级缓存区
域。二级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。二级缓存中的value,就是查询出的
结果对象。
二级缓存是mapper级别的。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该
namespace下的二级缓存。
二级缓存的实现步骤:
1.在config文件中开启二级缓存总开关,如下:
<settings>
<setting name="cacheEnabled" value="true"></setting>
</settings>
2.在Mapper文件中使用二级缓存:
<cache type="二级缓存的供应商"></cache>
如果使用EhCache,则如下配置
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
3.缓存的对像必须实现序列化接口,如果类存在父类,那么父类也要实现序列化。(二级缓存数据有可能写入磁盘)
4.引数二级缓存供应商,这里以EhCache为例
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
5.配置该二级缓存的管理策略
在resources目录下引入ehcache.xml,在文件中配置缓存管理策略
<!--ehcache.xml-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!--缓存对像写入磁盘-->
<diskStore path="java.io.tmpdir"/>
<!--
1.maxElementsInMemory: 缓存空间大小
2.eternal:缓存对像是否一直存在
3.timeToIdleSeconds:缓存中空闲对像生存的时间
4.timeToLiveSeconds:缓存中对像生存的最长时间
5.maxElementsOnDisk:缓存到磁盘的最大空间
6.memoryStoreEvictionPolicy:缓存对像剥离的算法
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
overflowToDisk="true"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--UserMapper.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.UserMapper">
<!--该Mapper范围内的查询都使用二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<!--二级缓存-->
<select id="selectByCache2" resultType="User">
select * from User where id = #{id}
</select>
</mapper>
//Mapper接口
public interface UserMapper {
User selectByCache2(int id);
}
//service
/**
* 二级缓存测试
* @param id
* @return
*/
public void findByCache2(int id){
//从第一个session对像关联数据
SqlSession session = DBUtil.openSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectByCache2(id);
session.close();
//从第二个session对像中关联数据
SqlSession session2 = DBUtil.openSqlSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectByCache2(id);
session2.close();
//从第三个session对像中关联数据
SqlSession session3 = DBUtil.openSqlSession();
UserMapper mapper3 = session3.getMapper(UserMapper.class);
User user3 = mapper3.selectByCache2(id);
session3.close();
System.out.println(user);
System.out.println(user2);
System.out.println(user3);
}
//测试结果
DEBUG [main] - Cache Hit Ratio [mapper.UserMapper]: 0.0 //第一次缓存命中率
DEBUG [main] - Opening JDBC Connection
EBUG [main] - Created connection 690521419.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2928854b]
DEBUG [main] - ==> Preparing: select * from User where id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2928854b]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2928854b]
DEBUG [main] - Returned connection 690521419 to pool.
DEBUG [main] - Cache Hit Ratio [mapper.UserMapper]: 0.5//第二次缓存命中率
DEBUG [main] - Cache Hit Ratio [mapper.UserMapper]: 0.6666666666666666//第三次缓存命中率