美文网首页
SpringBoot与缓存使用及原理(转)

SpringBoot与缓存使用及原理(转)

作者: dinel | 来源:发表于2019-07-15 22:57 被阅读0次

    下面我就开始介绍springboot中的缓存:

    首先了解下JSR107、Spring缓存抽象等等概念。

    一 JSR107(下面会有具体Springboot代码演示)

    Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
    1 CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。

    2 CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。

    3 Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
    4 Entry是一个存储在Cache中的key-value对.

    5 Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

    如下图所示:

    二 Spring缓存抽象(下面会有具体Springboot代码演示)

    Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;
    1 Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;

    2 Cache接口下Spring提供了各种xxxCache的实现,如RedisCache,EhCacheCache , ConcurrentMapCache等;每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果返回给用户。下次直接从缓存中获取。

    3 使用Spring缓存抽象时我们需要关注以下两点;

    第一点就是确定方法需要被缓存以及他们的缓存策略 ,第二点就是从缓存中读取之前缓存存储的数据,如下图所示:

    了解jdbc的朋友就会很清楚,这就跟面向jdbc编程是一个道理,统一一个规范,统一面向jdbc编程。

    三 缓存注解(下面会有具体Springboot代码演示)

    同样支持spel表达式

    四 缓存使用(下面会有具体Springboot代码演示)

    要在Springboot中使用缓存需要以下几步:

    第一步: 导入spring-boot-starter-cache模块

    第二步: @EnableCaching开启缓存

    第三步: 使用缓存注解

    下面开始演示代码: 先说明一下我使用的是IntelliJ IDEA,这是一个非常不错的软件,用过eclipse的人再来用IDEA会有不一样的感觉,当然IDEA需要的内存要求会高些。有需要的朋友可以去官网下载,IDEA(https://www.jetbrains.com/idea/)是 JetBrains 公司的产品, 公司旗下还有其他产品,比如:WebStorm:用于开发 JavaScript、 HTML5、 CSS3 等前端技术; Android Studio:用于开发android(google 基于 IDEA 社区版进行迭代); PhpStorm; RubyMine; PyCharm; AppCode:用于开发 OC/Swift; CLion:用于开发 C/C++等。

    1 首先在pom.xml文件中引入坐标地址

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

    我们从图中可以看到cache这个模块导入进来了。

    2 在主程序中开启缓存注解

    @SpringBootApplication
    @EnableCaching
    public class Springboot07CacheApplication {
    
       public static void main(String[] args) {
          SpringApplication.run(Springboot07CacheApplication.class, args);
       }
    }
    

    3 开始测试代码,首先做好准备

    javaBean如下:

    package com.lxj.cache.bean;
    import java.io.Serializable;
    public class Employee  implements Serializable{
       private Integer id;
       private String lastName;
       private String email;
       private Integer gender; //性别 1男  0女
       private Integer dId; 
       public Employee() {}
       public Employee(Integer id, String lastName, String email, Integer gender, Integer dId) {
          super();
          this.id = id;
          this.lastName = lastName;
          this.email = email;
          this.gender = gender;
          this.dId = dId;
       } 
       public Integer getId() {
          return id;
       }
       public void setId(Integer id) {
          this.id = id;
       }
       public String getLastName() {
          return lastName;
       }
       public void setLastName(String lastName) {
          this.lastName = lastName;
       }
       public String getEmail() {
          return email;
       }
       public void setEmail(String email) {
          this.email = email;
       }
       public Integer getGender() {
          return gender;
       }
       public void setGender(Integer gender) {
          this.gender = gender;
       }
       public Integer getdId() {
          return dId;
       }
       public void setdId(Integer dId) {
          this.dId = dId;
       }
       @Override
       public String toString() {
          return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", dId="
                + dId + "]";
       }
    }
    

    controller层如下:

    @RestController
    public class EmployeeController {
    
        @Autowired
        EmployService employService;
        @GetMapping("/emp/{id}")
        public Employee getEmpById(@PathVariable("id") Integer id) {
            Employee empById = employService.getEmpById(id);
            return empById;
        }
    }
    

    service层如下:

    @CacheConfig(cacheNames = "emp")
    @Service
    public class EmployService {
    
        @Autowired
        EmploeeMapper emploeeMapper;
    
        @Cacheable(cacheNames = {"emp"})
        public Employee getEmpById(Integer id){
            System.out.println("查询" + id + "号员工");
            Employee employee = emploeeMapper.getEmpById(id);
            return  employee;
        }
    }
    

    mapper接口如下:

    @Mapper
    public interface EmploeeMapper {
        @Select("SELECT * FROM employee WHERE id = #{id}")
        public Employee getEmpById(Integer id);
        @Update("UPDATE employee SET lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} WHERE id = #{id}")
        public  void updateEmpById(Employee employee);
        @Delete("DELETE * FROM employee WHERE id = #{id}")
        public void deleteEmpById(Integer id);
    
        @Insert("INSERT INTO employee(lastName,email,gender,d_id) VALUES(#{lastName},#{email},#{gender},#{dId})")
        public  void InsertEmp(Employee employee);
    
        @Select("SELECT * FROM employee WHERE lastName = #{lastName}")
        public Employee getEmpByLastName(String lastName);
    }
    

    application.properties如下:

    spring.datasource.username=root
    spring.datasource.password=xxxxx
    spring.datasource.url=jdbc:mysql://localhost:3306/springCache
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    
    #开启驼峰命名法
    mybatis.configuration.map-underscore-to-camel-case=true
    
    #打印sql语句日志
    logging.level.com.lxj.cache.mappers=debug
    

    控制台打印配置信息

    debug=true
    sql语句如下:

    DROP TABLE IF EXISTS `employee`;
    CREATE TABLE `employee` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `lastName` varchar(255) DEFAULT NULL,
      `email` varchar(255) DEFAULT NULL,
      `gender` int(2) DEFAULT NULL,
      `d_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    整个工程结构:

    4 测试

    运行项目,打开浏览器输入 http://localhost:8080/emp/1 ,可以看到浏览器返回的值

    再来看看IEDA的控制台打印情况

    可以看到第一次获取数据是从数据库中获取的,再次输入 http://localhost:8080/emp/1

    可以看到并没有查询数据库,而是从缓存中获取的数据,这说明缓存起作用了,下面来分析下标记缓存的方法:

    @Cacheable(cacheNames = {"emp"})
    public Employee getEmpById(Integer id){
        System.out.println("查询" + id + "号员工");
        Employee employee = emploeeMapper.getEmpById(id);
        return  employee;
    }
    

    @Cacheables 能够根据方法的请求参数对其结果进行缓存

    cacheNames 缓存的名称,也就是在缓存中有一个叫emp的名字来标识不同的缓存组件。

    其他的参数在文章上面有介绍,详细介绍请看上文,下面看看@CachePut的功能。

    service有如下方法:

    // @CachePut: 既调用方法,又更新缓存数据;同步更新缓存
    // 修改了数据库的某个数据,同时更新缓存
    // 运行:
    // 1.先调用目标方法
    // 2.将目标方法的结果缓存起来

        @CachePut(key = "#result.id")
        public Employee updateEmp(Employee employee){
            System.out.println("updateEmp "+employee);
            emploeeMapper.updateEmpById(employee);
            return  employee;
        }
    

    controller如下:

    @GetMapping("/emp")
    public Employee updateEmp(Employee employee){
        Employee emp = employService.updateEmp(employee);
        return  emp;
    }
    

    我们更新id=1的员工 信息,返回了更新后的值

    这个时候我再查询id=1的员工

    看看控制台打印情况,可以看到只有之前更新时打印的数据,并没有从数据库查数据

    下面看看@CacheEvict

    // @CacheEvict:缓存清除
    // key:指定要清除的数据
    // allEntries = true : 指定清除这个缓存中的所有数据
    // beforeInvocation=fales: 缓存的清除是否在方法之前执行
    // 默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
    // beforeInvocation=true 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除

        @CacheEvict(beforeInvocation = true)
        public void deleteEmp(Integer id){
              System.out.println("delteEmp: " + id);
              int i = 101/0;
              emploeeMapper.deleteEmpById(id);
        }
    @GetMapping("/delEmp")
    public  String deleteEmp(Integer id){
        employService.deleteEmp(id);
        return "success";
    }
    

    首先从浏览器输入 http://localhost:8080/emp/1 ,将1号员工进行缓存

    可以看到已经缓存1号员工,接着输入 http://localhost:8080/delEmp?id=1 将1号员工删除

    这里有异常是因为有一句int i = 101/0 所以异常,但是不影响结果,这里主要是测试添加的参数,如下

    然后再来查询1号员工

    可以看到缓存被清除,重新从数据库中获取缓存。

    五 总结

    关于这篇博客就到这里,这是关于SpringBoot缓存的基本用法,有什么问题可以提出来,在下一篇文章,博主会讲讲关于SpringBoot中Cache的原理,会进行源码Debug,希望对大家有用。

    作者:刘信坚的博客
    来源:CSDN
    原文:https://blog.csdn.net/qq_38974634/article/details/80650810
    版权声明:本文为博主原创文章,转载请附上博文链接!

    相关文章

      网友评论

          本文标题:SpringBoot与缓存使用及原理(转)

          本文链接:https://www.haomeiwen.com/subject/dskakctx.html