SpringBoot整合Redis,RedisTemplate和注解两种方式

引入jar

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

注解方式使用 Redis 缓存

启动类

在启动类上加注解 @EnableCaching

@SpringBootApplication
@EnableCaching
public class SellApplication {
	public static void main(String[] args) {
		SpringApplication.run(SellApplication.class, args);
	}
}

添加缓存

在需要加缓存的方法上添加注解 @Cacheable(cacheNames = “product”, key = “product”),

cacheNames 和 key 都必须填,如果不填 key ,默认的 key 是当前的方法名,更新缓存时会因为方法名不同而更新失败。

如在订单列表上加缓存

	@RequestMapping(value = "/list", method = RequestMethod.GET)
    @Cacheable(cacheNames = "product", key = "product")
    public ResultVO list() {
 
        // 1.查询所有上架商品
        List<ProductInfo> productInfoList = productInfoService.findUpAll();
 
        // 2.查询类目(一次性查询)
        //用 java8 的特性获取到上架商品的所有类型
        List<Integer> categoryTypes = productInfoList.stream().map(e -> e.getCategoryType()).collect(Collectors.toList());
        List<ProductCategory> productCategoryList = categoryService.findByCategoryTypeIn(categoryTypes);
 
        List<ProductVO> productVOList = new ArrayList<>();
        //数据拼装
        for (ProductCategory category : productCategoryList) {
            ProductVO productVO = new ProductVO();
            //属性拷贝
            BeanUtils.copyProperties(category, productVO);
            //把类型匹配的商品添加进去
            List<ProductInfoVO> productInfoVOList = new ArrayList<>();
            for (ProductInfo productInfo : productInfoList) {
                if (productInfo.getCategoryType().equals(category.getCategoryType())) {
                    ProductInfoVO productInfoVO = new ProductInfoVO();
                    BeanUtils.copyProperties(productInfo, productInfoVO);
                    productInfoVOList.add(productInfoVO);
                }
            }
            productVO.setProductInfoVOList(productInfoVOList);
            productVOList.add(productVO);
        }
 
        return ResultVOUtils.success(productVOList);
    }

更新缓存

在需要更新缓存的方法上加注解: @CachePut(cacheNames = “prodcut”, key = “product”)

注意

cacheNames 和 key 要跟 @Cacheable() 里的一致,才会正确更新。

@CachePut() 和 @Cacheable() 注解的方法返回值要一致

删除缓存

在需要删除缓存的方法上加注解:@CacheEvict(cacheNames = “prodcut”, key = “product”),执行完这个方法之后会将 Redis 中对应的记录删除。

其他注解

cacheNames 也可以统一写在类上面, @CacheConfig(cacheNames = “product”) ,具体的方法上就不用写。

@CacheConfig(cacheNames = "product")
public class BuyerOrderController {
    @PostMapping("/cancel")
	@CachePut(key = "order")
    public ResultVO cancel(@RequestParam("openid") String openid,
                           @RequestParam("orderId") String orderId){
        buyerService.cancelOrder(openid, orderId);
        return ResultVOUtils.success();
    }
}

Key 也可以动态设置为方法的参数

@GetMapping("/detail")
@Cacheable(cacheNames = "prodcut", key = "#openid")
public ResultVO<OrderDTO> detail(@RequestParam("openid") String openid,
                             @RequestParam("orderId") String orderId){
    OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
    return ResultVOUtils.success(orderDTO);
}

如果参数是个对象,也可以设置对象的某个属性为 key。比如其中一个参数是 user 对象,key 可以写成 key="#user.id"

RedisTemplate 使用

与使用注解方式不同,注解方式可以零配置,只需引入依赖并在启动类上加上 @EnableCaching 注解就可以使用;而使用 RedisTemplate 方式麻烦些,需要做一些配置。

Redis 配置

第一步还是引入依赖和在启动类上加上 @EnableCaching 注解。

然后在 application.yml 文件中配置 Redis

spring:
  redis:
    port: 6379
    database: 0
    host: 127.0.0.1
    password:
    jedis:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0
    timeout: 5000ms

然后写个 RedisConfig.java 配置类


 
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
 
import java.net.UnknownHostException;
 
 
@Configuration
public class RedisConfig {
 
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
 
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
 
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
 
    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

StringRedisTemplate 与 RedisTemplate

RedisTemplate 对五种数据结构分别定义了操作

redisTemplate.opsForValue();

操作字符串

redisTemplate.opsForHash();

操作hash

redisTemplate.opsForList();

操作list

redisTemplate.opsForSet();

操作set

redisTemplate.opsForZSet();

操作有序set

如果操作字符串的话,建议用 StringRedisTemplate 。

StringRedisTemplate 与 RedisTemplate 的区别
StringRedisTemplate 继承了 RedisTemplate。

RedisTemplate 是一个泛型类,而 StringRedisTemplate 则不是。

StringRedisTemplate 只能对 key=String,value=String 的键值对进行操作,RedisTemplate 可以对任何类型的 key-value 键值对操作。

他们各自序列化的方式不同,但最终都是得到了一个字节数组,殊途同归,StringRedisTemplate 使用的是 StringRedisSerializer 类;RedisTemplate 使用的是 JdkSerializationRedisSerializer 类。反序列化,则是一个得到 String,一个得到 Object

两者的数据是不共通的,StringRedisTemplate 只能管理 StringRedisTemplate 里面的数据,RedisTemplate 只能管理 RedisTemplate中 的数据。

应用

@Autowired
RedisTemplate redisTemplate;
 
@Autowired
StringRedisTemplate stringRedisTemplate;


 
import com.solo.coderiver.user.dataobject.UserLike;
import com.solo.coderiver.user.dto.LikedCountDTO;
import com.solo.coderiver.user.enums.LikedStatusEnum;
import com.solo.coderiver.user.service.LikedService;
import com.solo.coderiver.user.service.RedisService;
import com.solo.coderiver.user.utils.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
 
@Service
@Slf4j
public class RedisServiceImpl implements RedisService {
 
    @Autowired
    RedisTemplate redisTemplate;
 
    @Autowired
    LikedService likedService;
 
    @Override
    public void saveLiked2Redis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.LIKE.getCode());
    }
 
    @Override
    public void unlikeFromRedis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.UNLIKE.getCode());
    }
 
    @Override
    public void deleteLikedFromRedis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
    }
 
    @Override
    public void incrementLikedCount(String likedUserId) {
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, 1);
    }
 
    @Override
    public void decrementLikedCount(String likedUserId) {
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1);
    }
 
    @Override
    public List<UserLike> getLikedDataFromRedis() {
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        List<UserLike> list = new ArrayList<>();
        while (cursor.hasNext()) {
            Map.Entry<Object, Object> entry = cursor.next();
            String key = (String) entry.getKey();
            //分离出 likedUserId,likedPostId
            String[] split = key.split("::");
            String likedUserId = split[0];
            String likedPostId = split[1];
            Integer value = (Integer) entry.getValue();
 
            //组装成 UserLike 对象
            UserLike userLike = new UserLike(likedUserId, likedPostId, value);
            list.add(userLike);
 
            //存到 list 后从 Redis 中删除
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
        }
 
        return list;
    }
 
    @Override
    public List<LikedCountDTO> getLikedCountFromRedis() {
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
        List<LikedCountDTO> list = new ArrayList<>();
        while (cursor.hasNext()) {
            Map.Entry<Object, Object> map = cursor.next();
            //将点赞数量存储在 LikedCountDT
            String key = (String) map.getKey();
            LikedCountDTO dto = new LikedCountDTO(key, (Integer) map.getValue());
            list.add(dto);
            //从Redis中删除这条记录
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);
        }
        return list;
    }
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值