前言
最近在做项目优化,数据库缓存是优化的一部分,所以整理了相关使用方法
mybatis缓存
作为一个半自动化的持久层框架,mybatis自带了一级缓存和二级缓存,目的是为了减轻数据库的访问压力,增加程序性能。比如当程序短时间内多次去调用相同的sql时,第一次会去数据库拿数据,然后放在缓存中,一定时间内再调用相同的sql就会去缓存中拿数据。
一级缓存和二级缓存
一级缓存是以sqlsession为单位的,同一个sqlsession,连续进行两次相同的sql查询,然后在close,第一次会查数据库,第二次会查缓存。
二级缓存是以mapper为单位的。mybatis一般是以mapper接口和xml文件组成持久层,在一个xml文件中,所有sql语句的namespace是相同的,所以他们公用一个二级缓存,就是所谓的以mapper为单位。
当我们使用缓存时(不论一级还是二级),为了避免脏读,每次执行insert,delete,update这样的commit操作之后,都要清空存。也就是说,在同一个sqlsession下,不要连续进行select-->update-->select这样类似的操作,update之后要及时关闭sqlssesion以达到清空缓存的效果
spring结合mybatis使用
一级缓存
一级缓存默认打开,并且我暂时没发现可以全局关闭的方法。(如果有知道的可以留言告诉我,感谢)
上面提到了使用一级缓存时,commit操作之后要及时清空缓存,但是我们在用spring结合mybatis的时候并没有这样做,直接执行mapper的方法进行连续curd操作也不会有问题。不用奇怪,这是因为spring通过代理,使用sqlsessionTemplete代替sqlsession,每次执行mapper的方法后都会关闭session,达到了清空缓存的效果。
验证
// 测试类
@Test
public void cacheTest() {
service.transactionDemo();
}
//service实现类
@Override
public void transactionDemo() {
String s1 = t1dao.selectname();
String s2 = t1dao.selectname();
}
从日志来看,两次都去数据库查询了。这是因为每次查完都会关闭session,所以一级缓存在这个时候是不生效的。(虽然不生效,但是每次查询还是会放入缓存,然后再清空,感觉不太好,但是又没有发现可以全局关闭的地方)
如果想要生效的话,在service实现类方法上添加事物注解,这样在事物内就不会关闭session(首先要确定配置的事物一定要生效)
//service实现类
@Override
@Transactional()
public void transactionDemo() {
String s1 = t1dao.selectname();
String s2 = t1dao.selectname();
}
从日志来看只查询了一次数据库。
二级缓存
二级缓存默认是全局打开的。
想要使用的话,在ssm框架下找到mybatis配置文件,添加
<settings>
<!-- 开启二级缓存(默认是开的,这里写出来是为了方便代码维护) -->
<setting name="cacheEnabled" value="true" />
</settings>
在dao层对应的xml里添加标签
<cache eviction="LRU" size="512" flushInterval="60000" readOnly="true"/>
如果是springboot项目,没有mybatis的xml配置文件,只需要在dao层接口添加注解
@Cacheable
然后xml文件里同样添加cache标签就可以。
验证
//service实现类
@Override
public void transactionDemo() {
String s1 = t1dao.selectname();
String s2 = t1dao.selectname();
}
@Test
public void cacheTest() {
service.transactionDemo();
}
//xml中的sql
<cache eviction="LRU" size="512" flushInterval="60000" readOnly="true"/>
<select id="selectname" resultType="java.lang.String" >
SELECT name FROM test where id = '1'
</select>
代码中去掉了service的事物注解,这样一级缓存会失效,上面已经验证过了,在没有开启二级缓存的情况下会查询2次数据库,现在开启了二级缓存,预期的结果是只查询一次数据库。
结果符合预期,说明二级缓存生效。
局部控制
此外,当全局开启缓存的时候,如果想单独控制某个sql不使用缓存,也可以在sql层面去控制,在xml中的sql标签里添加属性即可
<select id="selectname" resultType="java.lang.String" flushCache="true" useCache="false">
SELECT name FROM test where id = '1'
</select>
flushCache属性为true,每次执行完sql会刷新缓存
useCache属性为false可以使单条sql不适用缓存
使用场景
在项目中何时使用缓存或者不适用缓存要一句情况而定,实时性较高的数据一般不用。并且在使用的时候容易造成脏读数据。
二级缓存还可以结合redis这样三方缓存框架进行缓存,方便管理。
如有错误,欢迎指正