欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot2.x整合redis实现缓存

程序员文章站 2022-07-07 11:37:52
...
导入redis依赖
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

springboot默认使用的cacheManager是ConcurrentMapCacheManager,引入redis后CacheManager变为RedisCacheManager。RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件。RedisCacheManager默认使用RedisTemplate操作redis。RedisTemplate 是默认使用jdk的序列化机制

application.properties中redis数据源
#redis
spring.redis.database=0
spring.redis.host=192.168.56.10
spring.redis.port=6379
缓存管理器(cacheManager)配置和redisTemplate配置
package com.liang.cache.config;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.*;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义CacheManager
 */
@Configuration
public class MyRedisConfig {

    //缓存生存时间
    private Duration timeToLive = Duration.ofDays(1);

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        //redis缓存配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(this.timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                .disableCachingNullValues();
        //缓存配置map
        Map<String,RedisCacheConfiguration> cacheConfigurationMap=new HashMap<>();
        //自定义缓存名,后面使用的@Cacheable的CacheName
        cacheConfigurationMap.put("default",config);
        cacheConfigurationMap.put("emp",config);
        //根据redis缓存配置和reid连接工厂生成redis缓存管理器
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .withInitialCacheConfigurations(cacheConfigurationMap)
                .build();
        return redisCacheManager;
    }


    //redisTemplate模板提供给其他类对redis数据库进行操作
    @Bean(name = "redisTemplate")
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setHashValueSerializer(valueSerializer());
        return redisTemplate;
    }

    //缓存键自动生成器
    @Bean
    public KeyGenerator myKeyGenerator() {
        return (target, method, params) -> {

            return method.getName()+"["+ Arrays.asList(params).toString()+"]";
        };
    }

   //redis键序列化使用StrngRedisSerializer
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    //redis值序列化使用json序列化器。默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
    //GenericJackson2JsonRedisSerializer:这种序列化方式不用自己手动指定对象的Class。所以其实我们就可以使用一个全局通用
    //的序列化方式了。使用起来和JdkSerializationRedisSerializer基本一样。
    private RedisSerializer<Object> valueSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }

}

操作redis时注入redisTemplate即可

@Autowired
 private RedisTemplate redisTemplate;

Redis常见的五大数据类型
String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)

  • redisTemplate.opsForValue()[String(字符串)]
  • redisTemplate.opsForList()[List(列表)]
  • redisTemplate.opsForSet()[Set(集合)]
  • redisTemplate.opsForHash()[Hash(散列)]
  • redisTemplate.opsForZSet()[ZSet(有序集合)]
体验缓存
1、开启基于注解的缓存 @EnableCaching
@MapperScan("com.liang.cache.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot08CacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot08CacheApplication.class, args);
    }

}

2、在方法上标注缓存注解即可
@Cacheable
@CacheEvict
@CachePut


@Cacheable()
    public Employee getEmpById(Integer id){
        System.out.println("查询第"+id+"员工");
        return employeeMapper.getEmpById(id);
    }

运行流程:
@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去查询缓存,
如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
几个属性:
cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;

key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
            编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
            getEmp[2]
keyGenerator:key的生成器;可以自己指定key的生成器的组件id
                 key/keyGenerator:二选一使用;
  

cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器

condition:指定符合条件的情况下才缓存;
            ,condition = "#id>0"
      condition = "#a0>1":第一个参数的值》1的时候才进行缓存

unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
           unless = "#result == null"
        unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
sync:是否使用异步模式
 /**
     * @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号员工没有在缓存中更新】
     *
     */
    @CachePut(key = "#employee.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp......"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }
 /**
     * @CacheEvict:缓存清除
     *  key:指定要清除的数据
     *  allEntries = true:指定清除这个缓存中所有的数据
     *  beforeInvocation = false:缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true:
     *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
     *
     *
     */
    @CacheEvict
    public void deleteEmp(Integer id){
        System.out.println("delete...."+id);
        employeeMapper.deleteEmpById(id);

    }
 // @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){
        return employeeMapper.getEmpByLastName(lastName);
    }

3、实体类要序列化

implements Serializable
相关标签: Redis学习