redis

       默认是ConcurrentMapCacheManager,创建的是ConcurrentMapCache组件,将数据保存在一个ConcurrentMap里面。

       开发中经常使用的是缓存的中间件。

       Springboot缓存redis---Springboot整合篇------10/11/12

        缓存的配置类:

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

      其他的配置什么时候开启?

      Springboot缓存redis---Springboot整合篇------10/11/12自动配置的。

      整合redis作为缓存:

                redis中文网进行学习。Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。

                 安装redis:docker的形式进行安装。

                 在dockerhub上搜索和下载。

                 docker中国有镜像加速的功能。

                  

docker pull registry.docker-cn.com/library/redis

             Springboot缓存redis---Springboot整合篇------10/11/12

     启动镜像:

docker run -d -p 6379:6379 --name myredis docker.io/redis

    运行docker

    安装redis的连接工具。Springboot缓存redis---Springboot整合篇------10/11/12

    建立连接:

             Springboot缓存redis---Springboot整合篇------10/11/12

测试下redis的常用的数据操作:

             Springboot缓存redis---Springboot整合篇------10/11/12     右键打开控制台。    

              Springboot缓存redis---Springboot整合篇------10/11/12

        Springboot缓存redis---Springboot整合篇------10/11/12

     get msg

      lpush

              Springboot缓存redis---Springboot整合篇------10/11/12

                  lpop mylist

                Springboot缓存redis---Springboot整合篇------10/11/12

                rpop  mylist

                集合的操作:

                            sadd myset zhangsan lisi

                           Springboot缓存redis---Springboot整合篇------10/11/12

                 sadd myset lisi

                        Springboot缓存redis---Springboot整合篇------10/11/120是已经有了lisi

                 smembers myset

                          Springboot缓存redis---Springboot整合篇------10/11/12

                 sismember myset wangwu

                        Springboot缓存redis---Springboot整合篇------10/11/12

10----------------------------------------------------------------------------------------------------------------

                 引入redis的starter:

                            学习找下springboot的官方文档。

                  Springboot缓存redis---Springboot整合篇------10/11/12

                  引入场景启动器

                  配置redis,只要指定下redis的主机地址。

                           

spring.redis.host=192.168.244.130

                                 

              测试:引入了redis的场景之后,

              Springboot缓存redis---Springboot整合篇------10/11/12

              就起作用了。

              看下自动配置主要做了什么?

               配置了两个东西:

                Springboot缓存redis---Springboot整合篇------10/11/12

                两个Template就和以前学的JDBSTempalte一样的。用的话只需要自动注入就可以。

                

package com.atguigu.cache;

import com.atguigu.cache.bean.Employee;
import com.atguigu.cache.mapper.EmployeeMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheApplicationTests {

    @Autowired
    EmployeeMapper employeeMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;  //操作k-v都是字符串的

    @Autowired
    RedisTemplate redisTemplate;  //k-v都是对象的

    @Test
    public void contextLoads() {
        Employee empById = employeeMapper.getEmpById(1);
        System.out.println(empById);
    }

    /**
     * Redis常见的五大数据类型
     *  String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)
     *  stringRedisTemplate.opsForValue()[String(字符串)]
     *  stringRedisTemplate.opsForList()[List(列表)]
     *  stringRedisTemplate.opsForSet()[Set(集合)]
     *  stringRedisTemplate.opsForHash()[Hash(散列)]
     *  stringRedisTemplate.opsForZSet()[ZSet(有序集合)]
     */
    @Test
    public void test01(){
        //给redis中保存数据
        stringRedisTemplate.opsForValue().append("msg","hello");
		String msg = stringRedisTemplate.opsForValue().get("msg");
		System.out.println(msg);
		stringRedisTemplate.opsForList().leftPush("mylist","1");
		stringRedisTemplate.opsForList().leftPush("mylist","2");
    }

}

   测试保存对象:

           

 //测试保存对象
    @Test
    public void test02(){
        Employee empById = employeeMapper.getEmpById(1);
        //默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
        redisTemplate.opsForValue().set("emp-01",empById);
        //1、将数据以json的方式保存
        //(1)自己将对象转为json
        //(2)redisTemplate默认的序列化规则;改变默认的序列化规则;
        //empRedisTemplate.opsForValue().set("emp-01",empById);
    }

  注意传的对象的前提必须是可序列化的:

            Springboot缓存redis---Springboot整合篇------10/11/12

      查看redis:

             Springboot缓存redis---Springboot整合篇------10/11/12

      都是序列化的结果。

      要想可视化的查看有两种方法:

          1.以对象转为json的方式保存

          2. 模型有序列化的规则:   Springboot缓存redis---Springboot整合篇------10/11/12

         Springboot缓存redis---Springboot整合篇------10/11/12

       Springboot缓存redis---Springboot整合篇------10/11/12

     默认的序列化器就是JDK的序列化器,我们自己写一个就可以了。

     

package com.atguigu.cache.config;


import com.atguigu.cache.bean.Department;
import com.atguigu.cache.bean.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.net.UnknownHostException;

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, Employee> empRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Employee> ser = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
        template.setDefaultSerializer(ser);
        return template;
    }
    
    
    /*@Bean
    public RedisTemplate<Object, Department> deptRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Department> template = new RedisTemplate<Object, Department>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Department> ser = new Jackson2JsonRedisSerializer<Department>(Department.class);
        template.setDefaultSerializer(ser);
        return template;
    }

    
    //CacheManagerCustomizers可以来定制缓存的一些规则
    @Primary  //将某个缓存管理器作为默认的
    @Bean
    public RedisCacheManager employeeCacheManager(RedisTemplate<Object, Employee> empRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate);
        //key多了一个前缀

        //使用前缀,默认会将CacheName作为key的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }

    @Bean
    public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate);
        //key多了一个前缀

        //使用前缀,默认会将CacheName作为key的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }*/


}

      Springboot缓存redis---Springboot整合篇------10/11/12

在这里复制一下。

 在测试类里面注入:

     

@Autowired
    RedisTemplate<Object, Employee> empRedisTemplate;
  //测试保存对象
    @Test
    public void test02(){
        Employee empById = employeeMapper.getEmpById(1);
        //默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
        //redisTemplate.opsForValue().set("emp-01",empById);
        //1、将数据以json的方式保存
        //(1)自己将对象转为json
        //(2)redisTemplate默认的序列化规则;改变默认的序列化规则;
        empRedisTemplate.opsForValue().set("emp-01",empById);
    }

   代码如上。

            Springboot缓存redis---Springboot整合篇------10/11/12

           直接改变序列化规则。

11----------------------------------------------------------------------------------------------------------------

                 原理:  Springboot缓存redis---Springboot整合篇------10/11/12        

                  debug=true:是自动配置的报告

                  Springboot缓存redis---Springboot整合篇------10/11/12

                Springboot缓存redis---Springboot整合篇------10/11/12 之前的就不匹配了

         为什么?

Springboot缓存redis---Springboot整合篇------10/11/12

先判断:给容器中放了一个缓存管理器:

Springboot缓存redis---Springboot整合篇------10/11/12

点进去RedisManager创建Cache

Springboot缓存redis---Springboot整合篇------10/11/12

              Springboot缓存redis---Springboot整合篇------10/11/12

               给我们的是RedisCache。

               

整合redis作为缓存
 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
 1、安装redis:使用docker;
 2、引入redis的starter
 3、配置redis
 4、测试缓存
 		原理: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的序列化机制
       4)、自定义CacheManager;

    缓存1号员工:

         http://localhost:8080/emp/1

         再次查询,发现不走数据库了,说明存到redis里面了。 

Springboot缓存redis---Springboot整合篇------10/11/12     

        发现是乱码是默认的jdk序列化的结果。

        原理:来到RedisCacheConfiguration

Springboot缓存redis---Springboot整合篇------10/11/12

帮我们创建了。

        注意上面的参数RedisTemplate<Object, Object>是RedisAutoConfiguration帮我们创建的,下面是源码:

        

/*
 * Copyright 2012-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.data.redis;

import java.net.UnknownHostException;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support.
 *
 * @author Dave Syer
 * @author Andy Wilkinson
 * @author Christian Dupuis
 * @author Christoph Strobl
 * @author Phillip Webb
 * @author Eddú Meléndez
 * @author Stephane Nicoll
 * @author Marco Aust
 * @author Mark Paluch
 */
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

}

  点进去默认用的序列化的机制是jdk的。

   所以我们自定义自己的Cachemanager:

               Springboot缓存redis---Springboot整合篇------10/11/12

  按照这个自己写.

       1.0和2.0区别很大停更。07:56

       

 private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive) {
        this.timeToLive = timeToLive;
    }
    

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }

      上面的是新版的。

                进入RedisCacheConfiguration。

                Springboot缓存redis---Springboot整合篇------10/11/12

    看这里没有的话才创建的,有的话就用我们的。

   重启进行测试:

              Springboot缓存redis---Springboot整合篇------10/11/12

      可以了。

      创建Deptservice。

       

package com.atguigu.cache.service;

import com.atguigu.cache.bean.Department;
import com.atguigu.cache.bean.Employee;
import com.atguigu.cache.mapper.DepartmentMapper;
import com.atguigu.cache.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;


@Service
public class DeptService {

    @Autowired
    DepartmentMapper departmentMapper;

    @Autowired
    EmployeeMapper employeeMapper;

    /**
     *  缓存的数据能存入redis;
     *  第二次从缓存中查询就不能反序列化回来;
     *  存的是dept的json数据;CacheManager默认使用RedisTemplate<Object, Employee>操作Redis
     *
     *
     * @param id
     * @return
     */
   @Cacheable(cacheNames = "dept")
   public Department getDeptById(Integer id){
        System.out.println("查询部门"+id);
        Department department = departmentMapper.getDeptById(id);
       return department;
    }

}

     开始查询:

             http://localhost:8080/dept/1

     第二次:走缓存,2.0的没有问题。

Springboot缓存redis---Springboot整合篇------10/11/12

       新老版本的配置对比:

package com.atguigu.cache.config;


import com.atguigu.cache.bean.Department;
import com.atguigu.cache.bean.Employee;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {

    @Bean
    public RedisTemplate<Object, Employee> empRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Employee> ser = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
        template.setDefaultSerializer(ser);
        return template;
    }


    /*@Bean
    public RedisTemplate<Object, Department> deptRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Department> template = new RedisTemplate<Object, Department>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Department> ser = new Jackson2JsonRedisSerializer<Department>(Department.class);
        template.setDefaultSerializer(ser);
        return template;
    }*/


    //CacheManagerCustomizers可以来定制缓存的一些规则
    /*@Primary  //将某个缓存管理器作为默认的
    @Bean
    public RedisCacheManager employeeCacheManager(RedisTemplate<Object, Employee> empRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(RedisCacheManager);
        //key多了一个前缀
        //使用前缀,默认会将CacheName作为key的前缀
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }*/

    private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive) {
        this.timeToLive = timeToLive;
    }


    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }



    /*@Bean
    public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate){
        RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate);
        //key多了一个前缀

        //使用前缀,默认会将CacheName作为key的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }*/


}

  最后一个知识点:

public Department getDeptById(Integer id){
        System.out.println("查询部门"+id);
        Department department = departmentMapper.getDeptById(id);

        //获取某个缓存
        Cache dept = cacheManager.getCache("dept");
        dept.put("dept:123",department);

        return department;
    }

         Springboot缓存redis---Springboot整合篇------10/11/12

Springboot缓存redis---Springboot整合篇------10/11/12

12-------------------------------------------------------------------------------------------------------------

   代码的github地址:https://github.com/FandyWw/springboot-01-cache-my

 

相关文章: