04.SpringBoot中集成Redis缓存

1、依赖

1.1、pom.xml

<!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

1.2、application.yaml

spring:
  redis:
    host: 127.0.0.1 # Redis服务器地址
    database: 0 # Redis数据库索引(默认为0)
    port: 6379 # Redis服务器连接端口
    password: # Redis服务器连接密码(默认为空)
    jedis:
      pool:
        max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 8 # 连接池中的最大空闲连接
        min-idle: 0 # 连接池中的最小空闲连接
    timeout: 3000ms # 连接超时时间(毫秒)

1.3、RedisConfig

package com.wnx.mall.tiny.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.cache.RedisCacheWriter;
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.time.Duration;

/**
 * @author by wangnaixing
 * @Description
 * @Date 2022/1/16 13:27
 */
@Configuration
@EnableCaching
public class RedisConfig  extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<Object> serializer = redisSerializer();
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedisSerializer<Object> redisSerializer() {
        //创建JSON序列化器
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }
    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //设置Redis缓存有效期为1天
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1));
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }

}

2、集成

2.1、ReidsService

package com.wnx.mall.tiny.service;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author by wangnaixing
 * @Description
 * @Date 2022/1/16 13:29
 */
public interface RedisService {
    /**
     * 保存属性
     * @param key
     * @param value
     * @param time
     */
    void set(String key,Object value,long time);

    /**
     * 保存属性
     * @param key
     * @param value
     */
    void set(String key,Object value);

    /**
     * 获取属性
     * @param key
     * @return
     */
    Object get(String key);

    /**
     * 删除属性
     * @param key
     * @return
     */
    Boolean del(String key);

    /**
     * 批量删除属性
     * @param keys
     * @return
     */
    Long del(List<String> keys);

    /**
     * 设置过期时间
     * @param key
     * @param time
     * @return
     */
    Boolean expire(String key,long time);

    /**
     * 判断是否有该属性
     * @param key
     * @return
     */
    Boolean hasKey(String key);

    /**
     * 按delta递增
     * @param key
     * @param delta
     * @return
     */
    Long incr(String key,long delta);

    /**
     * 按照delta值递减
     * @param key
     * @param delta
     * @return
     */
    public Long decr(String key, long delta);


    /**
     * 获取Hash结构中的属性
     * @param key
     * @param hashKey
     * @return
     */
    Object hGet(String key,String hashKey);

    /**
     * 向Hash结构中放入一个属性
     * @param key
     * @param hashKey
     * @param value
     * @param time
     * @return
     */
    Boolean hSet(String key,String hashKey,Object value,long time);

    /**
     * 直接设置整个Hash结构
     * @param key
     * @param map
     * @param time
     * @return
     */
    Boolean hSetAll(String key, Map<String,Object> map, long time);

    /**
     * 删除Hash结构中的属性
     * @param key
     * @param hashKey
     */
    void hDel(String key,Object...hashKey);


    /**
     * 判断Hash结构中是否有该属性
     * @param key
     * @param hashKey
     * @return
     */
    Boolean hHashKey(String key,String hashKey);

    /***
     * Hash结构中的属性递增
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    Long hIncr(String key,String hashKey,Long delta);


    /**
     * Hash结构中属性递减
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    Long hDecr(String key,String hashKey,Long delta);

    /**
     * 获取Set结构
     * @param key
     * @return
     */
    Set<Object> sMembers(String key);

    /**
     * 向Set结构中添加属性
     * @param key
     * @param value
     * @return
     */
    Long sAdd(String key,Object...value);

    /**
     * 是否为Set中属性
     * @param key
     * @param value
     * @return
     */
    Boolean sIsMember(String key,Object value);

    /**
     * 获取Set结构的长度
     * @param key
     * @return
     */
    Long sSize(String key);

    /**
     * 删除Set结构中的属性
     * @param key
     * @param values
     * @return
     */
    Long sRemove(String key,Object...values);


}

2.2、RedisServiceImpl

package com.wnx.mall.tiny.service.impl;

import com.wnx.mall.tiny.service.RedisService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author by wangnaixing
 * @Description
 * @Date 2022/1/16 13:29
 */
@Service
public class RedisServiceImpl implements RedisService {
    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    @Override
    public void set(String key, Object value, long time) {
        redisTemplate.opsForValue().set(key,value,time, TimeUnit.SECONDS);
    }

    @Override
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key,value);

    }

    @Override
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public Boolean del(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public Long del(List<String> keys) {
        return redisTemplate.delete(keys);
    }

    @Override
    public Boolean expire(String key, long time) {
        return redisTemplate.expire(key,time,TimeUnit.SECONDS);
    }

    @Override
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public Long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key,delta);
    }

    @Override
    public Long decr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key,-delta);
    }

    @Override
    public Object hGet(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key,hashKey);
    }

    @Override
    public Boolean hSet(String key, String hashKey, Object value, long time) {
        redisTemplate.opsForHash().put(key,hashKey,value);
        return expire(key,time);
    }

    @Override
    public Boolean hSetAll(String key, Map<String, Object> map, long time) {
        redisTemplate.opsForHash().putAll(key,map);
        return expire(key,time);
    }

    @Override
    public void hDel(String key, Object... hashKey) {
        redisTemplate.opsForHash().delete(key,hashKey);
    }

    @Override
    public Boolean hHashKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key,hashKey);
    }

    @Override
    public Long hIncr(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key,hashKey,delta);
    }

    @Override
    public Long hDecr(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key,hashKey,-delta);
    }

    @Override
    public Set<Object> sMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    @Override
    public Long sAdd(String key, Object... values) {
        return redisTemplate.opsForSet().add(key,values);
    }

    @Override
    public Boolean sIsMember(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key,value);
    }

    @Override
    public Long sSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    @Override
    public Long sRemove(String key, Object... values) {
        return redisTemplate.opsForSet().remove(key,values);
    }
}

3、测试

package com.wnx.mall.tiny.service;

import cn.hutool.core.bean.BeanUtil;
import com.wnx.mall.tiny.common.api.CommonPage;
import com.wnx.mall.tiny.mbg.model.PmsBrand;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author by wangnaixing
 * @Description
 * @Date 2022/1/16 13:38
 */
@SpringBootTest
public class RedisServiceTest {

    @Resource
    private RedisService redisService;
    @Resource
    private PmsBrandService pmsBrandService;

    //测试注解的获取
    @Test
    public void testAnnoGet(){
        PmsBrand pmsBrand = pmsBrandService.findById(1L);
        // key=mall::pms:brand:1 ttl=86393
        // value={"id":1,"name":"万和","firstLetter":"W","sort":0,"factoryStatus":1,"showStatus":1,"productCount":100,"productCommentCount":100,"logo":"http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg","bigPic":"","brandStory":"Victoria's Secret的故事"}
        //同理,修改,删除PmsBrand的时候,会根据key去删除对应缓存!
        PmsBrand  pmsBrand1 = (PmsBrand) redisService.get("mall::pms:brand:1");
        System.out.println(pmsBrand1);
    }
    //设置属性
    @Test
    public void set(){
        PmsBrand brand = pmsBrandService.findById(1L);
        redisService.set("brand:"+brand.getId(),brand);
        //key=brand:1 value=brand的JSON串!
    }
    //设置属性并指定了时间60秒
    @Test
    public void set2(){
        PmsBrand brand2 = pmsBrandService.findById(2L);
        redisService.set("brand:"+brand2.getId(),brand2,60);
        //key=brand:2 value=brand2的JSON串 ttl=60秒,会慢慢变成59 58 57 0秒的时候,会删除这个缓存,即缓存过期!
    }
    //取出属性
    @Test
    public void get(){
       //redisTemplate 内部会处理,把JSON串变成Object对象,可直接强制转换得到Model
        PmsBrand pmsBrand = (PmsBrand) redisService.get("brand:1");
        System.out.println(pmsBrand);
        //PmsBrand对象 [Hash = 1567145551, id=1, name=万和, firstLetter=W, sort=0, factoryStatus=1, showStatus=1, productCount=100, productCommentCount=100, logo=http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg, bigPic=, brandStory=Victoria's Secret的故事, serialVersionUID=1]
    }
    //根据Key删除属性
    @Test
    public void  del(){
        Boolean flag = redisService.del("brand:1");
        System.out.println(flag);//删除成功返回 true!
    }
    /**
     * 删除由key组成集合的属性
     * @throws InterruptedException 中短异常
     */
    @Test
    public void delAll() throws InterruptedException {
        //1.构造keys
        CommonPage<PmsBrand> page = pmsBrandService.findByPage(1, 3);
        List<String> keys = new ArrayList<>();
        for (PmsBrand brand : page.getList()) {
            redisService.set("brand:"+brand.getId(),brand);
            keys.add("brand:"+brand.getId());
        }
        //2.休眠3秒,这时你可在redis客户端发现 这brand:1 brand:2 brand:3 的三个缓存,值为Model的JSON串!
        Thread.sleep(3000);
        //3.执行完毕,这三个缓存没有了!
        redisService.del(keys);
    }
    //指定某个属性的过期时间
    @Test
    public void expire(){
        PmsBrand brand = pmsBrandService.findById(1L);
        redisService.set("brand:"+brand.getId(),brand);
        //此种方式可在已经创建了该缓存后,还想指定缓存过期时间的时候使用。
        redisService.expire("brand:"+brand.getId(),60);
    }
    //判断缓存是否存在该属性
    @Test
    public void hasKey(){
        PmsBrand brand = pmsBrandService.findById(1L);
        redisService.set("brand:"+brand.getId(),brand);
        Boolean hasKey = redisService.hasKey("brand:" + brand.getId());
        System.out.println("存在该属性:"+hasKey);//true
        redisService.del("brand:" + brand.getId());
    }
    // 让属性自增一个整型值,返回自增完毕的值
    @Test
    public void incr(){
        redisService.set("count",2);//要求存的必须是整型
        Long incr = redisService.incr("count", 1);
        System.out.println(incr);//3
    }
    //让属性自减一个整型值,返回自减完毕的值
    @Test
    public void decr(){
        redisService.set("count",2);//要求存的必须是整型
        Long incr = redisService.decr("count", 1);
        System.out.println(incr);//1
    }
    //设置key为mall 属性名为brand 属性值为brand对象的缓存
    @Test
    public void hSet(){
        PmsBrand brand = pmsBrandService.findById(1L);
        redisService.hSet("mall:brand:"+brand.getId(),"id",brand.getId(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"name",brand.getName(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"first_letter",brand.getFirstLetter(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"sort",brand.getSort(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"factory_status",brand.getFactoryStatus(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"show_status",brand.getShowStatus(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"product_count",brand.getProductCount(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"product_comment_count",brand.getProductCommentCount(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"logo",brand.getLogo(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"big_pic",brand.getBigPic(),60*24);
        redisService.hSet("mall:brand:"+brand.getId(),"brand_story",brand.getBrandStory(),60*24);
        String name = (String) redisService.hGet("mall:brand:1", "name");
        String logo = (String) redisService.hGet("mall:brand:"+brand.getId(), "logo");
        System.out.println(name+"---"+logo);
        // 我认为和string数据类型相比,我可以单独的取出来某个属性的值,而不是都是全部取出来!
        // 万和 --- http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg
    }

    //哈希结构的批量设置
    @Test
    public void hSetAll(){
        PmsBrand brand = pmsBrandService.findById(1L);
        //转换成map的话,map中的key就是 hashkey
        Map<String, Object> map = BeanUtil.beanToMap(brand);
        redisService.hSetAll("mall:brand:"+brand.getId(),map,60*60);
        String name = (String) redisService.hGet("mall:brand:1", "name");
        Integer productCount = (Integer) redisService.hGet("mall:brand:"+brand.getId(), "productCount");
        System.out.println(name+"---"+productCount);
        //万和---100
    }

    //选择性删除哈希结构的属性
    @Test
    public void hDel(){
        redisService.hDel("mall:brand:1","id","name");
    }

    //该hash结构中是否存在hashkey 是:返回true 不是:返回false
    @Test
    public void hHashKey(){
        //上一test 已经删除了 id name
        Boolean hashKey = redisService.hHashKey("mall:brand:1", "id");
        Boolean hashKey1 = redisService.hHashKey("mall:brand:1", "name");
        Boolean hashKey2 = redisService.hHashKey("mall:brand:1", "brandStory");
        System.out.println(hashKey); //false
        System.out.println(hashKey1); //false
        System.out.println(hashKey2); // true
    }
    //hash的自增和自减
    @Test
    public void hIncrAndhDecr(){
        //自增自减操作总是得到完成操作后的值
        Integer sort = (Integer) redisService.hGet("mall:brand:1", "sort");
        Long sortAdd1 = redisService.hIncr("mall:brand:1", "sort", 10L);
        Long sortReduce1 = redisService.hDecr("mall:brand:1","sort",1L);
        System.out.println(sort);//0 取出,初始值为0
        System.out.println(sortAdd1);//10
        System.out.println(sortReduce1);//9
    }

    //向Set结构中添加属性
    @Test
    public void sAdd(){
        //往set集合里添加元素1,2,3,返回值为成功操作的次数,如果存在相同元素,不会添加进去。
        Long sussCount = redisService.sAdd("mySet", 1, 2, 3);
        System.out.println(sussCount); //  3  0 第二次执行,返回0
    }
    //是否为Set集合中元素 ,如果是:返回true 如果不是:返回false
    @Test
    public void sIsMember(){
        Boolean flag = redisService.sIsMember("mySet", 1);
        Boolean flag2 = redisService.sIsMember("mySet", 4);
        System.out.println(flag);//true
        System.out.println(flag2); //false

    }
    //返回Set集合长度
    @Test
    public void sSize(){
        Long length = redisService.sSize("mySet");
        System.out.println(length);//3
    }

    //删除Set集合中某个元素
    @Test
    public void sRemove(){
        Long length = redisService.sSize("mySet"); //3
        redisService.sRemove("mySet",1,2);
        length = redisService.sSize("mySet");
        System.out.println(length);//1

    }




}