SpringBoot高级应用——SpringBoot与缓存

(一)、Spring缓存抽象

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们的开发。

     1)、几个重要概念&缓存注解

在这里插入图片描述

(二)、基础环境的搭建

  1. 创建项目

    在这里插入图片描述

    1. 导入数据库文件

      /*
      Navicat MySQL Data Transfer
      
      Source Server         : 本地
      Source Server Version : 50528
      Source Host           : 127.0.0.1:3306
      Source Database       : springboot_cache
      
      Target Server Type    : MYSQL
      Target Server Version : 50528
      File Encoding         : 65001
      
      */
      
      SET FOREIGN_KEY_CHECKS=0;
      
      -- ----------------------------
      -- Table structure for department
      -- ----------------------------
      DROP TABLE IF EXISTS `department`;
      CREATE TABLE `department` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `departmentName` varchar(255) DEFAULT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      -- ----------------------------
      -- Table structure for employee
      -- ----------------------------
      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;
      
      
    2. 创建javabean
      在这里插入图片描述

    3. 整合Mybatis操作数据库

      spring:
        datasource:
          url: jdbc:mysql://localhost:3306/spring_cache?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
          username: root
          password: XHHP0913
          driver-class-name: com.mysql.jdbc.Driver
      mybatis:
        mapper-locations: classpath:mybatis/mapper/*.xml
        configuration:
          map-underscore-to-camel-case: true 
      
      package com.crud.springboot.mapper;
      
      import com.crud.springboot.bean.Employee;
      import org.apache.ibatis.annotations.Mapper;
      import org.springframework.stereotype.Repository;
      
      @Mapper
      @Repository
      public interface EmployeeMapper {
      
          public Employee getEmpById(Integer id);
      
          public void updateEmp(Employee employee);
      
          public void deleteEmpById(Integer id);
      
          public void insertUser(Employee employee);
      
          public Employee getEmpByLastName(String lastName);
      }
      
      
      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.crud.springboot.mapper.EmployeeMapper">
          <select id="getEmpById" resultType="com.crud.springboot.bean.Employee">
              select * from employee where id=#{id}
          </select>
      
          <update id="updateEmp">
              update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}
          </update>
      
          <delete id="deleteEmpById">
              delete from employee where id=#{id}
          </delete>
      
          <insert id="insertUser">
              insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},,#{dId})
          </insert>
      
          <select id="getEmpByLastName" resultType="com.crud.springboot.bean.Employee">
              select * from employee where lastName=#{lastName}
          </select>
      </mapper>
      
  2. 搭建简单的Service层和Controller层
    在这里插入图片描述

(三)、快速体验缓存(@Cacheable)

  1. 开启基于注解的缓存

    @MapperScan("com.crud.springboot.mapper")
    @SpringBootApplication
    @EnableCaching
    public class Springboot01CacheApplication
    
  2. 标注缓存注解即可

        @Cacheable(cacheNames = {"emp","temp"})
        public Employee getEmp(Integer id){
            System.out.println("查询2号员工");
            Employee emp = employeeMapper.getEmpById(id);
            return emp;
        }
    

    备注:
    1. 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
    2.CacheMananger管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件都有自己唯一一个名字
    3.@Cacheable有如下几个可配置属性

属性配置内容
cacheNames/value指定缓存的名字
key缓存数据时使用的key;可以用它来指定。默认是使用方法参数的值
keyGeneratorkey的生成器:可以自己指定key的生成器的组件id
cacheMananger指定缓存管理器;或者cacheResolver指定缓存解析器
condition指定符合条件的情况下才缓存
unless否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
sync是否使用异步模式
备注key/keyGenerator 二选一使用、cacheMananger/cacheResolver 二选一使用

            4.支持SPEL表达式
在这里插入图片描述

(四)、@CachePut

@CachePut(value = {"emp"},key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("update"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }
  1. @CachePut:既调用方法,又更新缓存数据;
  2. 修改数据库的某个数据,同时更新缓存
  3. 运行时机:
    1、先调用目标方法
    2、将目标方法的结果缓存起来
  4. 测试样例:
    1、首先查询一号员工,查询数据库,会把结果放在缓存中
    2、再次查询一号员工,直接从缓存中获取结果
    3、跟新一号员工的数据,调用updateEmp的方法,会将更新的结果放入缓存中
    4、再次查询一号员工,发现结果更新了,但是并未查询数据库
    注意:@CachePut的key要和@Cacheable的key相同才能更新缓存

(五)、@CacheEvict

/**
     * @CacheEvict 清除缓存
     * 可以使用属性 allEntries = true  清空所有的缓存
     * 可以使用属性 beforeInvocation = true  在方法执行之前清空缓存(默认是false)
     * @param id
     */
    @CacheEvict(cacheNames = {"emp"},key = "#id")
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        employeeMapper.deleteEmpById(id);
    }
  1. @CacheEvict:用于清空缓存
  2. 修改数据库的某个数据,同时更新缓存
  3. 运行时机:
    1、用于删除数据时清空缓存;
  4. 测试样例:
    1、首先查询一号员工,查询数据库,会把结果放在缓存中
    2、再次查询一号员工,直接从缓存中获取结果
    3、删除一号员工
    4、再次查询一号员工,发现需要再次查询数据库才能获得结果
    注意:1、可以使用属性 allEntries = true 清空所有的缓存
               2、可以使用属性 beforeInvocation = true 在方法执行之前清空缓存(默认false)

(六)、@Caching

@Caching(
            cacheable = {
                @Cacheable(value="emp",key = "#lastName")
            },
            put = {
                    @CachePut(value="emp",key="#result.id"),
                    @CachePut(value = "emp",key = "#result.email")
            }
    )
    public Employee getEmpByLastName(String lastName){
        Employee emp = employeeMapper.getEmpByLastName(lastName);
        return emp;
    }
  1. @Caching:是一个组合注解,可以组合@Cacheable、@CachePut、@CacheEvict

(七)、@CacheConfig

@Service
@CacheConfig(cacheNames = "emp")
public class EmployeeService {
  1. @CacheConfig:抽取缓存的公共配置

(八)、整合Redis作为缓存

SpringBoot默认使用的是ConcurrentMapCacheManager=ConcurrentMapCache;
开发中使用缓存中间件:redis、memcached、ehcache;

(1)、在虚拟机上搭建redis环境
(2)、引入SpringBoot的Redis starter
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
(3)、配置Redis
spring:
  datasource:
    redis:
      host: 192.168.56.102
(4)、测试缓存

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

  1. 引入redis的starter,容器中保存的是RedisCacheManager

  2. RedisCacheManager 帮我们创建RedisCache来作为缓存组件

  3. RedisCache通过操作Redis来缓存数据

  4. 默认保存数据 k-v 都是通过Object;利用序列化保存;如何保存为json:
    1、引入了redis的starter,cacheManager变为RedisCacheManager;
    2、默认创建的CacheManager操作Redis的时候使用的是RedisTemplate<Object, Object>(默认使用jdk的序列化机制)

  5. 自定义CacheManager:

    	/**
         * 2.0版本RedisCacheManager
         * @param redisConnectionFactory
         * @param empRedisTemplate
         * @return
         */
        @Bean
        public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
            //初始化一个RedisCacheWriter
            RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
            //设置CacheManager的值序列化方式为json序列化
            RedisSerializer<Employee> jsonSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
            RedisSerializationContext.SerializationPair<Employee> pair = RedisSerializationContext.SerializationPair
                    .fromSerializer(jsonSerializer);
            RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig()
                    .serializeValuesWith(pair);
            //初始化RedisCacheManager
            return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
        }
    
    (5)、指定统一的CacheManager

    如果不指定不同的CacheManager会导致混乱,出现错误
    在这里插入图片描述

需要为不同方法指定对应的CacheManager,并且要选择一个Primary的CacheManager

 	@Primary
    @Bean
    public RedisCacheManager deptRedisCacheManager(RedisConnectionFactory redisConnectionFactory){
        //初始化一个RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //设置CacheManager的值序列化方式为json序列化
        RedisSerializer<Department> jsonSerializer = new Jackson2JsonRedisSerializer<Department>(Department.class);
        RedisSerializationContext.SerializationPair<Department> pair = RedisSerializationContext.SerializationPair
                .fromSerializer(jsonSerializer);
        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(pair);
        //初始化RedisCacheManager
        return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
    }
	@Cacheable(cacheNames = "dept",cacheManager = "deptRedisCacheManager")
    public Department getDeptById(Integer id){
        Department  department=departmentMapper.getDeptById(id);
        return department;
    }
(6)、如需在编码中使用缓存
    @Qualifier("deptCacheManager")
    RedisCacheManager  deptCacheManager;

    //@Cacheable(cacheNames = "dept",cacheManager = "deptRedisCacheManager")
    public Department getDeptById(Integer id){
        Department  department=departmentMapper.getDeptById(id);
        //获取某个缓存
        Cache dept = deptCacheManager.getCache("dept");
        dept.put("dept",department);
        return department;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值