热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

SpringBoot与缓存使用及原理(上),Go语言社区,Golang程序员人脉社

下面我就开始介绍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:用于开发 JavascriptHTML5CSS3 等前端技术; Android Studio:用于开发android(google 基于 IDEA 社区版进行迭代)PhpStormRubyMinePyCharmAppCode:用于开发 OC/SwiftCLion:用于开发 C/C++等。

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

org.springframework.boot spring-boot-starter-cache


我们从图中可以看到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,希望对大家有用。

      





推荐阅读
  • 程序员妻子吐槽:丈夫北漂8年终薪3万,存款情况令人意外
    一位程序员的妻子在网上分享了她丈夫在北京工作八年的经历,月薪仅3万元,存款情况却出乎意料。本文探讨了高学历人才在大城市的职场现状及生活压力。 ... [详细]
  • 资源推荐 | TensorFlow官方中文教程助力英语非母语者学习
    来源:机器之心。本文详细介绍了TensorFlow官方提供的中文版教程和指南,帮助开发者更好地理解和应用这一强大的开源机器学习平台。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 作为一名新手,您可能会在初次尝试使用Eclipse进行Struts开发时遇到一些挑战。本文将为您提供详细的指导和解决方案,帮助您克服常见的配置和操作难题。 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
author-avatar
平凡咸伟
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有