mybatis包含了一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存。缓存可以极大的提高查询的效率
mybatis系统当中默认定义了两级缓存:一级缓存和二级缓存
一级缓存:默认情况之下,只有一级缓存开启(sqlSession级别的缓存)
二级缓存:需要手动开启配置,需要局域namespace级别的缓存。
一级缓存失效的场景:
sqlSession不同sqlSession相同,查询条件不同sqlSession相同,两次查询之间执行了增删改操作!sqlSession相同,手动清除一级缓存1.mybatis一级缓存是SqlSession级别的缓存,
2.在操作数据库的时候需要构造sqlsession对象,在对象中有一个数据结构(HashMap)用于存储数据。
3.不同的Sqlsession之间的缓存数据区域是互相不影响的,是独立的
4.一级缓存是框架默认为我们开启的,我们不需要做任何配置
//key:statementId和sql语句
//value:查询结果
一级缓存是sqlsession级别的缓存,也叫本机缓存,因为每一个用户来执行查询的时候都需要sqlsession来执行。为了避免每次都去查询数据库。mybatis把缓存的数据存到sqlsession的本地缓存里面,如果sqlsession里面有的可以直接从本地缓存去读取查询的数据。要是想实现跨Ssqlsession这个级别的话,需要用到二级缓存。就是当多个用户去查询数据的时候,只要有任何一个sqlsession拿到了数据,就会放入到二级缓存里面,其它的sqlsession可以直接从二级缓存里面查询数据。
需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。
二级缓存:二级缓存开启步骤:二级缓存是mapper级别的缓存,多个Sqlsession去操作一个mapper.xml语句,多个sqlseesion共用一个二级缓存,
//key:hashCode + statementId + SQL语句
//value:查询结果
<!‐‐ 开启二级缓存 ‐‐>
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--使用二级缓存-->
<cache eviction="FIFO" #收回策略
flushInterval="6000" #刷新间隔
size="512" #引用数目
readOnly="true"/> #只读
eviction回收策略:
LRU(最近最少使用的):移除最长时间不被使用的对象,这是默认值。
FIFO(先进先出):按对象进入缓存的顺序来移除它们。
SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象。
WEAK(弱引用):更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushinterval(刷新间隔)
可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。
默认情况不设置,即没有刷新间隔,缓存仅仅在调用语句时刷新。
size(引用数目)
可以被设置为任意正整数,要记住缓存的对象数目和运行环境的可用内存资源数目。默认值是1024 。
readOnly(只读)
属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改, 这提供了很重要的性能优势。
可读写的缓存会通过序列化返回缓存对象的拷贝,这种方式会慢一些,但是安全,因此默认是 false。
④. 在select标签上使用二级缓存
<select id="findById" parameterType="int" resultType="User" useCache="true" >
select * from user where id = #{id}
</select>
二级缓存测试:
public class UserTest {
private InputStream in = null;
private SqlSession session1 = null;
private SqlSession session2 = null;
private UserDao mapper1 = null;
private UserDao mapper2 = null;
@Test
public void findById() throws IOException {
// 1.加载SqlMapConfig配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建sqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//3.sqlSessionFactory创建sqlSession
SqlSession sqlSession1 = factory.openSession();
SqlSession sqlSession2 = factory.openSession();
//4.通过Session创建UserDao接口代理对象
UserDao mapper1 = sqlSession1.getMapper(UserDao.class);
UserDao mapper2 = sqlSession2.getMapper(UserDao.class);
User user1 = mapper1.find(1);
System.out.println(user1.toString());
// 将其一级缓存的数据放进二级缓存中,并清空一级缓存
sqlSession1.commit();
System.out.println("-----------------");
User user2 = mapper2.find(1);
System.out.println(user2.toString());
System.out.println(user1 == user2);
// 将其一级缓存的数据放进二级缓存中,并清空一级缓存
sqlSession2.commit();
//7.关闭资源
sqlSession1.close();
sqlSession2.close();
resourceAsStream.close();
}
}
1、一级缓存和二级缓存原理
在sqlsession里面会有一个 executor,每一个executor里面会有一个localcache对象,当用户发起查询的时候,mybatis会根据执行语句,在localcache去查找,如果命中了就直接把这个数据返回,没有的话,再去数据库里面查找出来,ch再写入到localcae里面。所以一级缓存的生命周期是sqlsession。
需要注意的是,在多个sqlsession或者分布式环境下,可能会因为一级缓存,导致一个脏读的情况。
2、二级缓存实现原理是在executor上,引入了一个叫cachingexecutor的一个装饰器, 所以在进入一级缓存之前,会先通过cachingexecutor进行二级缓存 的查询。开启二级缓存之后会被多个sqlsession共享。所以它是一个全局的缓存。所以它的查询流程就变成了先查二级缓存,再查一级缓存,然后再去查数据库。
mybatis的二级缓存相当一级缓存来说,它实现了sqlsession之间缓存数据的一个共享,同时缓存粒度,也能控制到namespace一个级别,并且还通过cache这样的一个接口,来实现不同缓存实现类的一个组合, 对cache的可控也更高了。
关注关注了解更多:
标签:缓存,一级,sqlsession,查询,二级缓存,SqlSession,Mybatis From: https://www.cnblogs.com/liubaihui/p/17527262.html