springboot整合redis做緩存操作


Spring Cache簡介

Spring可以根據@Cacheable 、@CachePut 、@CacheEvict 、@EnableCaching等注解就可以實現對數據的緩存功能。

添加依賴

由於SpringBoot 2.x中默認並沒有使用Redis連接池,所以需要在pom.xml中添加commons-pool2的依賴;

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!--redis依賴配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在application.yml配置文件中,添加redis的配置

spring:
  redis:
    # Redis服務器地址
    host: 192.168.1.111
    # Redis數據庫索引(默認為0)
    database: 0
    # Redis服務器連接端口
    port: 6379
    # Redis服務器連接密碼(默認為空)
    password:
    # 連接超時時間
    timeout: 1000ms
    lettuce:
      pool:
        # 連接池最大連接數
        max-active: 8
        # 連接池最大空閑連接數
        max-idle: 8
        # 連接池最小空閑連接數
        min-idle: 0
        # 連接池最大阻塞等待時間,負值表示沒有限制
        max-wait: -1ms

添加redisConfig配置類,配置redisTemplate模板

// 開啟redis緩存功能
@EnableCaching
// 備注這是一個配置類
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * 配置redis模板文件
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<Object> serializer = redisSerializer();
        // 創建RedisTemplate<String, Object>對象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 配置連接工廠
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // redis key 序列化方式使用stringSerial
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // redis value 序列化方式使用jackson
        redisTemplate.setValueSerializer(serializer);
        // redis hash key 序列化方式使用stringSerial
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // redis hash value 序列化方式使用jackson
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 配置序列化
     * @return
     */
    @Bean
    public RedisSerializer<Object> redisSerializer() {
        // 定義Jackson2JsonRedisSerializer序列化對象
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會報異常
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }

    /**
     * 自定義緩存管理器
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                .defaultCacheConfig()
                // 設置value 為自動轉json的Object
             .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer()))
                // 緩存有效期為一天
                .entryTtl(Duration.ofDays(1));
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }

}

常用注解

@EnableCaching

開啟緩存功能,一般放在啟動類上,也可放在redisConfig配置文件上。

@Cacheable

使用該注解的方法當緩存存在時,會從緩存中獲取數據而不執行方法,當緩存不存在時,會執行方法並把返回結果存入緩存中。

一般使用在查詢方法上,可以設置如下屬性:

value:緩存名稱(必填),指定緩存的命名空間;
key:用於設置在命名空間中的緩存key值,可以使用SpEL表達式定義,如果不指定,則缺省按照方法的所有參數進行組合;
unless:條件符合則不緩存;
condition:條件符合則緩存。

執行這個方法的時候,會先去redis中,根據ceshi::user:id(這個id就是前段傳來的id)作為key去查找,如果找到直接返回redis中的數據

如果沒有找到就執行該方法,由於unless屬性,當返回結果為空就不存入redis中,這里的result是固定寫法,指的就是當前返回值User

當不指定key的時候,就會以方法名作為key,這里就是以id作為key。

@Cacheable(value = "ceshi", key = "'user:'+#id", unless = "#result==null")
@GetMapping("{id}")
public User getUserById(@PathVariable("id") Long id) {
    User user = new User();
    user.setAge(1);
    user.setUserId(10L);
    user.setUsername("張三");
    user.setPassword("123");
    user.setToken("2223334455:333:332");
    return user;
}

image-20201112191107096

ceshi::user:id在工具中會以:分隔,所以就會出現圖片中的ceshi下一級為空的樣子。

@CachePut

使用該注解的方法每次執行時都會把返回結果存入緩存中

一般使用在新增方法上,但是本人覺得新增可以不增加緩存,當查詢到這個數據的時候沒有再添加緩存即可,可以設置如下屬性:

value:緩存名稱(必填),指定緩存的命名空間;
key:用於設置在命名空間中的緩存key值,可以使用SpEL表達式定義,如果不指定,則缺省按照方法的所有參數進行組合;
unless:條件符合則不緩存;
condition:條件符合則緩存。

// 更新ceshi 緩存
@CachePut (value= "ceshi" ,key= "#account.getName()" ) 
public Account updateAccount(Account account) {
   return updateDB(account);
}

@CacheEvict

使用該注解的方法執行時能夠根據一定的條件對緩存進行清空。

一般使用在更新或刪除方法上,可以設置如下屬性:

value:緩存名稱(必填),指定緩存的命名空間;
key:用於設置在命名空間中的緩存key值,可以使用SpEL表達式定義;
condition:條件符合則緩存。

allEntries:是否清空所有緩存內容,缺省為 false,如果指定為 true,則方法調用后將立即清空所有緩存

beforeInvocation:是否在方法執行前就清空,缺省為 false,如果指定為 true,則在方法還沒有執行的時候就清空緩存,缺省情況下,如果方法執行拋出異常,則不會清空緩存

// 清空key為ceshi::user:id 的緩存
@CacheEvict(cacheNames = "ceshi", key = "'user:'+#id")
@DeleteMapping("{id}")
public int deleteObject(@PathVariable("id") Long id) {
    return 0;
}

// 清空ceshi 所有緩存
@CacheEvict (value= "ceshi" ,allEntries= true ) 
public void reload() {
    reloadAll()
}
 
// 清空ceshi下 userName.length() <=4的緩存
@Cacheable (value= "ceshi" ,condition= "#userName.length() <=4" ) 
public Account getAccountByName(String userName) {
  // 方法內部實現不考慮緩存邏輯,直接實現業務
  return getFromDB(userName);
}

但是以上的做緩存都是粒度比較大的,如果想單獨做一些緩存,設置特定的時間什么的,就需要用到以下的工具類

redis工具類

/**
 * spring redis 工具類
 **/
@Component
public class RedisCache {
    
    @Autowired
    public RedisTemplate redisTemplate;

    /**
     * 緩存基本的對象,Integer、String、實體類等
     *
     * @param key   緩存的鍵值
     * @param value 緩存的值
     */
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 緩存基本的對象,Integer、String、實體類等
     *
     * @param key      緩存的鍵值
     * @param value    緩存的值
     * @param timeout  時間
     * @param timeUnit 時間顆粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 設置有效時間
     *
     * @param key     Redis鍵
     * @param timeout 超時時間
     * @return true=設置成功;false=設置失敗
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 設置有效時間
     *
     * @param key     Redis鍵
     * @param timeout 超時時間
     * @param unit    時間單位
     * @return true=設置成功;false=設置失敗
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 獲得緩存的基本對象。
     *
     * @param key 緩存鍵值
     * @return 緩存鍵值對應的數據
     */
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 刪除單個對象
     *
     * @param key
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 刪除集合對象
     *
     * @param collection 多個對象
     * @return
     */
    public long deleteObject(final Collection collection) {
        return redisTemplate.delete(collection);
    }

    /**
     * 緩存List數據
     *
     * @param key    緩存的鍵值
     * @param values 待緩存的List數據
     * @return 緩存的對象
     */
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 獲得緩存的list對象
     *
     * @param key 緩存的鍵值
     * @return 緩存鍵值對應的數據
     */
    public <T> List<T> getCacheList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 緩存Set
     *
     * @param key     緩存鍵值
     * @param dataSet 緩存的數據
     * @return 緩存數據的對象
     */
    public <T> long setCacheSet(final String key, final Set<T> dataSet) {
        Long count = redisTemplate.opsForSet().add(key, dataSet);
        return count == null ? 0 : count;
    }

    /**
     * 獲得緩存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 緩存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 獲得緩存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 往Hash中存入數據
     *
     * @param key   Redis鍵
     * @param hKey  Hash鍵
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 獲取Hash中的數據
     *
     * @param key  Redis鍵
     * @param hKey Hash鍵
     * @return Hash中的對象
     */
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 獲取多個Hash中的數據
     *
     * @param key   Redis鍵
     * @param hKeys Hash鍵集合
     * @return Hash對象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    /**
     * 獲得緩存的基本對象列表
     *
     * @param pattern 字符串前綴
     * @return 對象列表
     */
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }
    
}

參考:http://www.macrozheng.com/#/reference/spring_data_redis

http://www.ruoyi.vip/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM