简单介绍:
在之前,我们介绍了关于MyBatis的一级缓存机制,之前我们说过,一级缓存是基于SqlSession的对同一条SQL语句多次查询的时候,会将第一次查询的结果缓存到内存中,之后的所有的相同的查询会直接从内存中获取数据,这样就避免了多次的连接数据库造成的资源浪费问题。但是此时还有一个问题,就是如果是多个SqlSession执行同一条SQL语句的时候呢?
因为一级缓存是基于同一个SqlSession的,所以当查询方法的对象并不是同一个的时候,就不会使用一级缓存机制,这样显然是并不能满足我们的使用的,所以这时候就出现了范围更大,使用更灵活的二级缓存,基于mapper的缓存机制。
二级缓存的机制是基于mapper的,所以他的策略是基于同一个SQL映射文件的所有的查询语句都会被缓存,这样即使SqlSession并不是同一个,也会触发缓存机制。
使用方法:
二级缓存需要我们进行手动配置,配置的方法也非常的简单,首先我们需要在mybatis的核心配置文件中开启namespace下的二级缓存,然后到SQL映射文件中添加一个新的标签,叫做<cache>标签即可。
在SQL映射文件中:
这个标签就是空的,只需要存在即可
代码实现:
在配置二级缓存之前,我们首先来看没有配置二级缓存的时候,当我们使用多个SqlSession对同一个SQL语句进行查询的时候是什么样的情况:
可以看到,我们在最上面的红框中定义了两个SqlSession,在中间对两个SqlSession进行赋值,然后在最下面使用两个SqlSession执行相同的SQL语句,结果如下:
可以看到,运行结果很明显就是由两个SqlSession发出的,会有两个connection和执行了两次SQL语句,最终输出两条结果。
现在我们打开二级缓存,首先是MyBatis的核心配置文件:
然后是SQL映射文件:
完成这样的配置之后,我们再来执行刚才的代码,观察控制台的输出结果:
很明显,这次的查询结果比之前的简短了很多,并且最明显的就是,第二次查询并没有出现connection和SQL语句的执行,这就表示我们完成了两个不同的SqlSession查询同一SQL语句的时候依然可以进入缓存机制。
<cache>的属性和在默认情况下实现的功能:
常用属性:
readOnly:表示缓存以只读的形式保存,当有新的缓存进入的时候,会直接删除旧的缓存,如果不配置这个属性,会导致一个报错。
flushInterval:刷新间隔,以毫秒为单位。即缓存的刷新间隔,默认不刷新
size:引用数目,默认为1024
eviction:回收策略,有四个值,分别对应四种不同的缓存回收策略,默认是LRU,即移除最长时间不使用的缓存。其次是FIFO,按照缓存进入的时间移除最早进入的缓存。
默认功能:
1.映射文件中所有的select语句都会被缓存下来。
2.映射文件中所有的增删改操作都会导致缓存被清空
3.缓存默认使用LRU回收机制,即回收最长时间不使用的缓存。
4.没有刷新间隔,不会刷新缓存。
5.缓存会默认存储列表集合或者对象的1024个引用,这个值可以通过size属性进行更改
6.缓存是可读/可写的,这也就表示对象的检索不是共享的,缓存可以安全的被调用者修改,而不同担心会修改其他调用者的缓存。
注意点:
这里唯一需要注意的就是如果<cache>标签没有设置readonly的值为true会报错,报错如下:
这个报错是由于,出现了新的缓存,而旧的缓存没有配置只读属性,所以他会默认的将缓存写入到硬盘中进行持久化存储,而我们对象到文件的持久化存储在没有实现序列化接口的时候就会报这个错误,所以我们可以选择让对象实现序列化接口,或者给<cache>标签没有设置readonly的值为true的形式来解决这个报错,我们推荐使用第二种添加属性的方式。