美文网首页
SpringBoot高级应用——SpringBoot与缓存

SpringBoot高级应用——SpringBoot与缓存

作者: XHHP | 来源:发表于2019-08-06 00:04 被阅读0次

(一)、Spring缓存抽象

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

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

image.png

(二)、基础环境的搭建

  1. 创建项目

    [图片上传失败...(image-fa9ada-1565021029707)]

    1. 导入数据库文件
    ```sql
    /*
    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;
    
    ```
3. 创建javabean
![在这里插入图片描述](https://img.haomeiwen.com/i18288748/74e1f92b3ce08199.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4. 整合Mybatis操作数据库
    ```yml
    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 
    ```
    ```java
    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
    <?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>
    ```
  1. 搭建简单的Service层和Controller层


    在这里插入图片描述

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

  1. 开启基于注解的缓存
```java
@MapperScan("com.crud.springboot.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot01CacheApplication
```
  1. 标注缓存注解即可

        @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;可以用它来指定。默认是使用方法参数的值
keyGenerator key的生成器:可以自己指定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;
    }

相关文章

网友评论

      本文标题:SpringBoot高级应用——SpringBoot与缓存

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