前言

最近在做项目优化,数据库缓存是优化的一部分,所以整理了相关使用方法

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();

    }

Spring Data JPA二级缓存 spring二级缓存作用_sql

 

从日志来看,两次都去数据库查询了。这是因为每次查完都会关闭session,所以一级缓存在这个时候是不生效的。(虽然不生效,但是每次查询还是会放入缓存,然后再清空,感觉不太好,但是又没有发现可以全局关闭的地方)

如果想要生效的话,在service实现类方法上添加事物注解,这样在事物内就不会关闭session(首先要确定配置的事物一定要生效)

//service实现类
    @Override
    @Transactional()
    public void transactionDemo() {
        String s1 = t1dao.selectname();
        String s2 = t1dao.selectname();

    }

Spring Data JPA二级缓存 spring二级缓存作用_sql_02

从日志来看只查询了一次数据库。

 

二级缓存

二级缓存默认是全局打开的。

想要使用的话,在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次数据库,现在开启了二级缓存,预期的结果是只查询一次数据库。

Spring Data JPA二级缓存 spring二级缓存作用_sql_03

结果符合预期,说明二级缓存生效。

 

局部控制

此外,当全局开启缓存的时候,如果想单独控制某个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这样三方缓存框架进行缓存,方便管理。

 

如有错误,欢迎指正