1. 程式人生 > >SpringBoot2整合Redis快取

SpringBoot2整合Redis快取

在學習springboot整合redis的時候遇到這樣一個奇怪的問題:我從資料庫中取得的物件已經放入了redis中,而且從redis的客服端也可以檢視到對應的key,開始的時候還是正常的,能正常的從快取中取得並返回我需要的類;但是過一段時間第二次訪問這個方法時(這時應該是到redis裡面取)丟擲了java.lang.ClassCastException異常,說你的com.test.PerSon類(假設你存入快取的是com.test.PerSon類),不能轉為com.test.PerSon類。

這個就比較奇怪了,最後在不知道怎麼回事的情況下把

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<optional>true</optional>

</dependency>

模組去掉了就正常了。這個也......;

1、pom檔案加入

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
			<version>2.0.3.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
		<!-- 要用redis連線池 必須有pool依賴-->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
			<version>2.5.0</version>
		</dependency>

2、application.properties 加入redis相關配置

spring.redis.host=192.168.19.173
spring.redis.port=6379
spring.redis.timeout=60s
# 資料庫連線超時時間,2.0 中該引數的型別為Duration,這裡在配置的時候需要指明單位
spring.redis.timeout=60s
# 連線池配置,2.0中直接使用jedis或者lettuce配置連線池
# 最大活躍連線數,負數為不限制
spring.redis.lettuce.pool.max-active=500
# 等待可用連線的最大時間,負數為不限制
spring.redis.lettuce.pool.max-wait=-1ms
# 最大空閒連線數
spring.redis.lettuce.pool.max-idle=100
# 最小空閒連線數
spring.redis.lettuce.pool.min-idle=20



3、啟動類加註解 

@EnableCaching

4、快取配置類

package com.ps.uzkefu.common;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Author:ZhuShangJin
 * Date:2018/6/25
 */
@Configuration
public class CacheConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);

        template.setValueSerializer(serializer);
        //使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
    //    redis快取和EhCache快取不能同時存在
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//        RedisCacheManager cacheManager = RedisCacheManager.create(redisConnectionFactory);

// 生成一個預設配置,通過config物件即可對快取進行自定義配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        config = config.entryTtl(Duration.ofMinutes(1))     // 設定快取的預設過期時間,也是使用Duration設定
                .disableCachingNullValues();     // 不快取空值

        // 設定一個初始化的快取空間set集合
        Set<String> cacheNames =  new HashSet<>();
        cacheNames.add("timeGroup");
        cacheNames.add("user");

        // 對每個快取空間應用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put("timeGroup", config);
        configMap.put("user", config.entryTtl(Duration.ofSeconds(120)));

        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)     // 使用自定義的快取配置初始化一個cacheManager
                .initialCacheNames(cacheNames)  // 注意這兩句的呼叫順序,一定要先呼叫該方法設定初始化的快取名,再初始化相關的配置
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }
}

5、

Service層應用快取(註解方式)

@Service
public class PersonService {

    @Autowired
    private PersonRepo personRepo;

   /**
     * @Cacheable 應用到讀取資料的方法上,先從快取中讀取,如果沒有再從DB獲取資料,然後把資料新增到快取中
    * unless 表示條件表示式成立的話不放入快取
     * @param username
     * @return
     */
    @Cacheable(value = "user", key = "#root.targetClass + #username", unless = "#result eq null")
    public Person getPersonByName(String username) {
        Person person = personRepo.getPersonByName(username);
        return person;
    }

   /**
    * @CachePut 應用到寫資料的方法上,如新增/修改方法,呼叫方法時會自動把相應的資料放入快取
     * @param person
     * @return
     */
    @CachePut(value = "user", key = "#root.targetClass + #result.username", unless = "#person eq null")
    public Person savePerson(Person person) {
        return personRepo.savePerson(person);
    }

   /**
    * @CacheEvict 應用到刪除資料的方法上,呼叫方法時會從快取中刪除對應key的資料
     * @param username
     * @return
     */
    @CacheEvict(value = "user", key = "#root.targetClass + #username", condition = "#result eq true")
    public boolean removePersonByName(String username) {
        return personRepo.removePersonByName(username) > 0;
    }

    public boolean isExistPersonName(Person person) {
        return personRepo.existPersonName(person) > 0;
    }
}