JSR107规范的缓存

spring缓存抽象来简化缓存开发

环境搭建

导入依赖

建表、创建javaBean
连接数据库配置

spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver  会根据连接自动判断,可以不写
#开启驼峰命名匹配规则
mybatis.configuration.map-underscore-to-camel-case=true
#打印日志
logging.level.com.sjg.cache.mapper=debug

使用注解mybatis

@Repository //或者@Mapper
public interface EmployeeMapper {@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 updateEmp(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);
}

主程序配置注解扫描

@RestController
public class EmployeeController {@AutowiredEmployeeService employeeService;@GetMapping("/emp/{id}")public Employee getEmployee(@PathVariable("id") Integer id){Employee emp = employeeService.getEmp(id);return emp;}
}

使用缓存

开启注解缓存

将方法返回值保存到缓存,如果再使用相同数据,直接取缓存

@Service
public class EmployeeService {@AutowiredEmployeeMapper employeeMapper;//将方法运行结果缓存,这样以后用到相同数据,直接从缓存取,不用调用方法从数据库查询@Cacheable(cacheNames = {"emp"})public Employee getEmp(Integer id){System.out.println("查询" + id + "员工");Employee emp = employeeMapper.getEmpById(id);return emp;}
}


原理:
* 1、自动配置类;CacheAutoConfiguration
* 2、缓存的配置类
* org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
* org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
* org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
* org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
* org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
* org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
* org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
* org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
* org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
* org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
* org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
* 3、哪个配置类默认生效:SimpleCacheConfiguration;
*
* 4、给容器中注册了一个CacheManager:ConcurrentMapCacheManager
* 5、可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
*
* 运行流程:
* @Cacheable:
* 1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
* (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
* 2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
* key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
* SimpleKeyGenerator生成key的默认策略;
* 如果没有参数;key=new SimpleKey();
* 如果有一个参数:key=参数的值
* 如果有多个参数:key=new SimpleKey(params);
* 3、没有查到缓存就调用目标方法;
* 4、将目标方法返回的结果,放进缓存中
*
* @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
* 如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
*
* 核心:
* 1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
* 2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator

可用的spEL

Cacheable调用时机:调用方法前,先看缓存里有没有缓存,没有再调方法

1、指定缓存的key:默认是方法的参数作为key,可以使用spEL表达式进行改变
比如这里我使用当前方法名和参数作为key 即getEmp[2]


还可以使用key生成器
自定义生成器,并放到容器中,

@Configuration
public class MyCacheConfig {//自定义缓存key的生成策略@Bean("myKeyGenerator")public KeyGenerator keyGenerator(){return new KeyGenerator(){@Overridepublic Object generate(Object o, Method method, Object... params) {return method.getName()+"["+ Arrays.asList(params).toString()+"]";}};}
}

这次我使用自己定义的key生成器

condition:符合条件才缓存
比如这里表示获取的第一个参数值大于1才缓存

unless:如果,则不
比如这里,如果第一个参数值为2,则不缓存

sync:是否使用异步模式,与unless冲突

CachePut

调用时机:先调用目标方法, 把方法结果放进缓存,也就是最后才把结果放到缓存

  • @CachePut:既调用方法,又更新缓存数据;同步更新缓存

    • 修改了数据库的某个数据,同时更新缓存;
    • 运行时机:
    • 1、先调用目标方法
    • 2、将目标方法的结果缓存起来
    • 测试步骤:
    • 1、查询1号员工;查到的结果会放在缓存中;
    •      key:1  value:lastName:张三
      
    • 2、以后查询还是之前的结果
    • 3、更新1号员工;【lastName:zhangsan;gender:0】
    •      将方法的返回值也放进缓存了;
      
    •      key:传入的employee对象  值:返回的employee对象;
      
    • 4、查询1号员工?
    •  应该是更新后的员工;
      
    •      key = "#employee.id":使用传入的参数的员工id;
      
    •      key = "#result.id":使用返回后的id
      
    •         @Cacheable的key是不能用#result
      
    •  为什么是没更新前的?【1号员工没有在缓存中更新】
      


可以使用#employee.id作为key,也可以用#result.id作为key,因为CachePut是执行完方法才把数据放到缓存,也就是此时得到了返回值,即更新结果

要保证查询和更新,更新到的是同一个key的值

流程梳理:前提我不指定更新方法中的key,也就是默认使用的是返回值作为key。
首先,执行查询方法,会先看缓存中是否有key为1的缓存,发现没有,就去执行方法,查询数据库,是将参数id=1作为key,值是返回结果emp对象
当执行更新操作时,逻辑不同,会首先执行方法,也就是更新操作,更新数据库后返回,那么方法参数emp作为key,返回结果emp作为值
这就导致更新操作执行了,但是缓存中放的对象却因为key的缘故似乎没有得到更新。
所以要保证更新和查询是同一个key,也就是我在更新方法注解中标明result.id

CacheEvit

Caching

当需要定义复杂的缓存规则时,可以使用caching

@CacheConfig(cacheNames = “emp”) 可以抽取缓存中的公共配置

使用redis缓存

默认使用的是ConcurrentMapCacheManager==ConcurrentMapCache;将数据保存在 ConcurrentMap<Object, Object>中
但是开发中使用缓存中间件;redis、memcached、ehcache;

当完成redis相关配置时,才会使用redis缓存

1、下载redis镜像

dockerhub

但是下载是连接的国外的仓库,速度慢
这里我使用
阿里云docker CE镜像源站

阿里云镜像加速


CentOS7安装

# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装 Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 开启Docker服务
sudo service docker start

详情见官方文档
版本校验

root@iZbp12adskpuoxodbkqzjfZ:$ docker version

如果要使用阿里云容器镜像加速服务,
使用加速器可以提升获取Docker官方镜像的速度
需要注册阿里云,会生成专属你的加速器地址,然后根据操作文档配置加速器,重启docker即可

运行redis镜像

首先查看docker images

[root@localhost ~]# docker images

-d后台运行
-p暴露端口,redis默认端口是6379,将虚拟机的6379端口映射到redis6379,
–name为redis起名
接着指定运行哪个docker镜像

[root@localhost ~]# docker run -d -p 6379:6379 --name myredis docker.io/redis

运行起来后成为docker容器

建立redis连接



右键打开控制台测试

整合redis作为缓存

开发文档中找到redis starter
引入
spring-boot-starter-data-redis

配置redis

连接redis

测试


测试保存对象

先保证对象可序列化

redis保存对象,默认使用jdk序列化机制,但是保存的数据不易查看

1、可以使用json方式保存
自定义序列化器
修改redis中的序列化工具

配置自己的序列化器

@Configuration
public class MyRedisConfig {@Beanpublic RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {RedisTemplate<Object, Employee> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);//json序列化器Jackson2JsonRedisSerializer<Employee> ser = new Jackson2JsonRedisSerializer<Employee>(Employee.class);template.setDefaultSerializer(ser);return template;}
}

注入并使用

 @AutowiredRedisTemplate<Object, Employee> empRedisTemplate;@Testpublic void test01(){//给redis保存数据
//        stringRedisTemplate.opsForValue().append("msg", "hello");String msg = stringRedisTemplate.opsForValue().get("msg");System.out.println(msg);}

这样就修改了默认的序列化规则,不再是jdk的序列化

缓存原理

原理:CacheManager===Cache 缓存组件来实际给缓存中存取数据

  •  1)、引入redis的starter,容器中保存的是 RedisCacheManager;
    
  •  2)、RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件;RedisCache通过操作redis缓存数据的
    
  •  3)、默认保存数据 k-v 都是Object;利用序列化保存;如何保存为json
    
  •          1、引入了redis的starter,cacheManager变为 RedisCacheManager;
    
  •          2、默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate<Object, Object>
    
  •          3、RedisTemplate<Object, Object> 是 默认使用jdk的序列化机制
    

当引入redis的starter后,缓存管理器就不是默认的,而是RedisCacheManager,默认的RedisCacheManager操作redis使用的是RedisTemplate的序列化器,这个序列化器使用的是jdk的序列化。所以我们要修改缓存管理器的序列化工具

自定义缓存管理器

 //自定义缓存管理器//缓存的数据存入redis,第二次再反序列化从缓存中查询出来@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)).disableCachingNullValues().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();}

这样就修改为json方式序列化和反序列化来保存对象

springBoot17_缓存:环境搭建、原理、Cacheable、CachePut、CacheEvit、Caching、阿里云镜像加速、整合redis作为缓存、缓存原理、自定义缓存相关推荐

  1. docker配置阿里云镜像加速、镜像和容器常用命令、docker镜像原理

    6. Docker 配置阿里镜像加速服务 6.1 docker 运行流程 6.2 docker配置阿里云镜像加速 查看自己的镜像加速地址(链接直达):https://cr.console.aliyun ...

  2. Springboot整合Redis,高并发下访问缓存与写入缓存

    1.配置Redis连接:添加pox.xml依赖: <!-- redis --><dependency><groupId>org.springframework.bo ...

  3. java底层原理书籍_不愧是阿里p8大佬!终于把Java 虚拟机底层原理讲清楚了,请签收...

    概述 JVM 的内存模型和 JVM 的垃圾回收机制一直是 Java 业内从业者绕不开的话题(实际调优.面试)JVM是java中很重要的一块知识,也是面试常问的问题之一,直至今天,仍然还有许多面试者在被 ...

  4. liunx 环境-配置docker阿里云镜像加速

    1.登录阿里云 注册 2.找到控制台 1.创建一个目录 sudo mkdir -p /etc/docker 2.配置自己镜像加速器 sudo tee /etc/docker/daemon.json & ...

  5. 09、环境-配置docker阿里云镜像加速、通过阿里云控制台找到镜像加速器

    1.访问阿里云 官网地址 https://www.aliyun.com/ 2.登录阿里云 3.点击控制台,找到镜像加速器 4.配置镜像加速器 sudo mkdir -p /etc/docker sud ...

  6. 分布式基础篇1——环境搭建(谷粒商城)

    一.项目简介 1.电商模式 2.项目前置知识 3.项目技术&特色 4.项目架构图 5.微服务划分图 二.分布式基础概念 1.微服务 2.集群&分布式&节点 3.远程调用 4.负 ...

  7. 谷粒商城项目篇1_分布式基础篇_分布式基础概念、环境搭建、创建项目

    写在前面 为丰富项目经验,特此学习B站开源视频<全网最强电商教程<谷粒商城>对标阿里P6/P7,40-60万年薪>希望通过此学习能巩固所学,将技术栈串接起来. 此项目三个阶段 ...

  8. Redis-学习笔记01【Redis环境搭建】

    Java后端 学习路线 笔记汇总表[黑马程序员] Redis-学习笔记01[Redis环境搭建] Redis-学习笔记02[Redis命令操作] Redis-学习笔记03[Redis持久化] Redi ...

  9. 谷粒商城笔记+踩坑(1)——架构、项目环境搭建、代码生成器

     导航: 谷粒商城笔记+踩坑汇总篇_谷粒商城笔记踩坑6_vincewm的博客-CSDN博客 目录 1.项目介绍 1.1 微服务架构图 1.2. 微服务划分图 2.项目环境搭建 2.1. 虚拟机搭建环境 ...

  10. Jeecg-Boot 快速开发平台,前后端分离—开发环境搭建

    目录索引: 前端开发环境搭建 安装开发工具 导入项目 后端开发环境搭建 安装开发工具 导入项目 第一部分: 前端开发环境搭建 一.安装开发工具 安装nodejs.webstrom.yarn,安装方法参 ...

最新文章

  1. msm8953+android8.1接听电话时声音由默认听筒输出改为外放输出
  2. VTK:图片之ImageStack
  3. 表示探索、探究的几个词
  4. Doris之动态分区(全面)
  5. VS2017编译OpenJDK,编译通过的工程包下载链接
  6. 日期,时间相关R代码
  7. 推荐系统(7):推荐算法之基于协同过滤推荐算法
  8. 亚马逊SP-API市场端点接口文档整理
  9. 平均数、中位数、众数 三者的联系与区别
  10. 2017CNCC会议总结(一)
  11. 亮相Google I/O,字节跳动是这样应用Flutter的
  12. 湖南天才少女姚婷:刚毕业就被华为156万年薪邀请,来历不简单
  13. nsfw什么颜色_“ NSFW”是什么意思,以及如何使用它?
  14. 黑马C++学习总结之对象的初始化和清理
  15. 迅睿cms微信抖音小程序生成管理系统V1.0开源
  16. [数据结构] UVa1471 Defense Lines 防线
  17. 软件产品案例分析——福州大学微信小程序
  18. vim自动补全插件:YouCompleteMe使用前需要做的准备工作随手记录
  19. 4|无线传感器网络与应用|无线传感器网络原理及方法-许毅版|考试知识点
  20. 机器学习项目2-葡萄酒质量和年份的关系

热门文章

  1. MySQL--查询5天之内过生日的同事中的闰年2月29日问题的解决过程
  2. n 个元素顺序入栈,则可能的出栈序列有多少种?转
  3. HBuilderX运行微信小程序启动失败
  4. 腾讯云 python sdk_腾讯云CDN python SDK
  5. axure 侧滑抽屉式菜单_Axure教程:原型设计之侧滑菜单
  6. HDU 5857 Median (推导)
  7. NH7020固件网口分析与platoSDR固件对比
  8. 安装打印机提示未能添加服务器,打印机未能链接到服务器
  9. 大数据经典实验案例-WordCount原理详解和代码书写
  10. 安装Office2007时出现1706错误的解决方案