JAVAspringboot

Spring Boot缓存

2019-11-19  本文已影响0人  ruoshy

概述

  Spring提供了对应用程序添加缓存的支持。从本质上讲,将缓存应用于方法上,从而根据缓存中的信息减少执行次数。当开发者调用一个方法时,将方法的参数和返回值作为Key/Value缓存起来,当再次调用这个方法时,如果缓存中存在对应数据,就从缓存中获取数据,否则再去执行该方法。

支持

Spring并没有提供缓存的实现,而是提供了一套Api,可以自由选择缓存的实现。目前Spring Boot支持的缓存有如下几种(Spring Boot会按顺序检测以下提供的程序):

可以通过设置属性来指定提供缓存的程序。

无论使用哪种缓存实现不同的只是缓存配置,使用的缓存注解是一致的

注解 介绍
@EnableCaching 启用S​​pring的注释驱动的缓存管理功能
@CacheConfig 当此批注出现在给定的类上时,它为该类中定义的任何缓存操作提供一组默认设置。
@Cacheable 表示可以缓存调用方法(或类中的所有方法)结果的注释。每次调用指定方法时,将进行缓存行为,检查是否已缓存该方法参数和结果。如果在缓存中找不到键的值,则将调用目标方法并将返回的值存储在关联的缓存中。
@CacheEvict 表示方法(或类上的所有方法)触发缓存逐出操作的注解。
@CachePut 表示方法(或类上的所有方法)触发缓存放置操作的注释。
@Caching 此批注可用作元批注,以创建具自定义组合批注。

一、Ehcache 2.x 缓存

在项目的pom.xml文件中添加以下依赖:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
添加缓存配置文件

如果存在Ehcache的依赖,并且在classpath下有名为ehcache.xml的文件,那么EhCacheCacheManager将会自动作为缓存的提供者。因此,在resources目录下创建ehcache.xml文件作为Ehcach缓存的配置文件。

如果未配置ehcache.xml,则Ehcache依赖包下的ehcache-failsafe.xml是ehcache的默认配置。

<ehcache>
    <!--diskStore元素是可选的。-->
    <!--如果为任何缓存启用了overflowToDisk或diskPersistent,则必须对其进行配置。-->
    <!--diskStore只有一个属性 - path。这是将在其中创建.data和.index文件的目录路径。-->
    <!--如果路径是Java系统属性,则将其替换为正在运行的VM中的值-->
    <!--user.home - 用户的主目录-->
    <!--user.dir - 用户的当前工作目录-->
    <!--java.io.tmpdir - 默认临时文件路径-->
    <!--ehcache.disk.store.dir - 在命令行上指定的系统属性(例:java -Dehcache.disk.store.dir=/u01/myapp/diskdir)-->
    <!--子目录可以在属性后指定 例:java.io.tmpdir/cache-->
    <diskStore path="java.io.tmpdir/cache"/>

    <!--强制性默认缓存配置-->
    <!--这些设置将应用于使用CacheManager.add(String cacheName)创建的缓存。-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <!--localTempSwap - 该策略允许缓存在缓存操作期间使用本地磁盘。磁盘存储是临时的,并在重新启动后清除。-->
        <!--当策略为"none"时,所有缓存都保留在内存中(磁盘无溢出,磁盘无持久性)。-->
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <cache name="student"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>
</ehcache>
缓存配置 <cache/>:
属性 介绍
name 设置缓存的名称,用于标识缓存。
maxElementsInMemory 设置在内存中创建的最大对象数(0 ==无限制)。
maxElementsOnDisk 设置将在DiskStore中维护的最大对象数。默认值为零,表示无限制。
eternal 设置元素是否一直存在。如果为true,超时将被忽略。
overflowToDisk 设置当内存中的缓存达到maxInMemory限制时元素是否可以溢出到磁盘。
timeToIdleSeconds 设置元素过期之前的空闲时间,即缓存创建以后最后一次访问缓存的时间到超时失效时的时间间隔。值为0表示无穷大,默认值为0。
timeToLiveSeconds 设置元素过期之前的生存时间,即从创建时间到元素过期之间的间隔。值为0表示一直存在,默认值为0。
diskPersistent 磁盘存储在虚拟机重新启动后是否仍然存在,默认值为false。
diskExpiryThreadIntervalSeconds 做元素失效监测以及清除工作的线程运行间隔时间,默认值为120秒。
diskSpoolBufferSizeMB 磁盘缓冲区大小,默认30MB(内部以字节为单位,设置的值转换为字节后不可超过正整数表示范围)。
memoryStoreEvictionPolicy 达到maxElementsInMemory限制后,将强制执行清除策略。默认策略是最近最少使用(LRU),其他可用策略先进先出(指定为FIFO)和不常用(指定为LFU)。
开启缓存

在项目的入口类上添加@EnableCaching注解开启缓存。

@EnableCaching
@SpringBootApplication
public class EhcacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(EhcacheApplication.class, args);
    }

}
创建数据接口
@Service
@CacheConfig(cacheNames = "student")
public class StudentService {

    @Resource
    private StudentMapper studentMapper;

    @Cacheable
    public Student findById(Integer id) {
        Student student = studentMapper.findById(id);
        System.out.println("查询 :" + JSON.toJSONString(student));
        return student;
    }

    @CachePut(key = "#student.id")
    public Student insert(Student student) throws Exception {
        int status = studentMapper.insert(student);
        if (status == 0) {
            throw new Exception("Insert failed");
        }
        System.out.println("插入 :" + JSON.toJSONString(student));
        return student;
    }

    @CacheEvict(key = "#student.id")
    public Student delete(Student student) throws Exception {
        int status = studentMapper.delete(student);
        if (status == 0) {
            throw new Exception("Delete failed");
        }
        System.out.println("删除 :" + JSON.toJSONString(student));
        return student;
    }

    @CachePut(key = "#student.id")
    public Student update(Student student) throws Exception {
        int status = studentMapper.update(student);
        if (status == 0) {
            throw new Exception("Update failed");
        }
        System.out.println("更新 :" + JSON.toJSONString(student));
        return student;
    }

}
创建请求接口
@RestController
@RequestMapping("/std")
public class StudentController {

    @Resource
    private StudentService studentService;

    /**
     * 查询
     */
    @RequestMapping("/sel")
    public String findById(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            student = studentService.findById(student.getId());
            msg.put("status", 200);
            msg.put("result", student);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSON.toJSONString(msg);
    }

    /**
     * 插入
     */
    @RequestMapping("/ins")
    public String insert(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.insert(student);
            msg.put("status", 200);
            msg.put("message", "插入成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "插入失败");
        }
        return JSON.toJSONString(msg);
    }


    /**
     * 删除
     */
    @RequestMapping("/del")
    public String delete(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.delete(student);
            msg.put("status", 200);
            msg.put("message", "删除成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "删除失败");
        }
        return JSON.toJSONString(msg);
    }

    /**
     * 更新
     */
    @RequestMapping("/upd")
    public String update(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.update(student);
            msg.put("status", 200);
            msg.put("message", "更新成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "更新失败");
        }
        return JSON.toJSONString(msg);
    }

}
测试

向数据库中添加数据:

(一) 查询

连续访问查询接口页面并观察输出信息:

查询 控制台

根据输出信息发现,在浏览器中多次获取数据,数据查询方法只执行了一遍。

(二) 更新

访问更新接口:

更新

再次访问查询接口:

查询

观察控制台:


控制台

发现访问更新接口后再次访问查询接口,查询接口并没有再次从数据库获取数据,而是从缓存中获取,所以更新接口返回的结果会覆盖指定参数键的缓存。

(三) 插入

访问插入接口:

插入

访问查询接口:

查询

观察控制台:

控制台

发现插入数据后再次查询并没有从数据库中获取数据,而是从缓存中获取。因为插入时对参数和返回的结果进行了缓存。

(四) 删除

访问删除接口:

删除

访问查询接口:

查询

观察控制台:

控制台

发现访问删除接口后数据库中的数据被删除,再次访问查询接口进行查询发现触发了查询方法,说明删除数据时缓存同时也被删除了。

二、Redis 单机缓存

和Ehcache一样,如果在classpath下存在Redis并且Redis已经配置好,此时会默认使用RedisCacheManager作为缓存的提供者。

在项目的pom.xml文件中添加以下依赖(与之前的依赖相比不同的只是缓存的提供者):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

添加项目配置:

spring:
  datasource:
    url: jdbc:mysql://xxx.xxx.xxx.xxx/user
    username: xxxx
    password: xxxxxx

  # 缓存配置
  cache:
    # 配置缓存名,多个缓存可使用逗号分隔(one,two)
    cache-names: student
    # 缓存存在时间
    redis:
      time-to-live: 120s
  redis:
    host: xxx.xxx.xxx.xxx
    port: xxxx

之后的流程与之前一致就不在阐述了。

上一篇下一篇

猜你喜欢

热点阅读