Java中操作Redis & SpringCache

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Java中操作Redis & SpringCache

 

在java中操作Redis

Controller

package com.zsh.controller.user;
@RestController("userDishController")
@RequestMapping("/user/dish")
@Slf4j
@Api(tags = "C端-菜品浏览接口")
public class DishController {
    @Autowired
    private DishService dishService;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> list(Integer categoryId) {
        // 查询
        List<DishVO> dishVO = dishService.findByCategoryId(categoryId);
        // 返回结果
        return Result.success(dishVO);
    }
}

image.gif

ServiceImpl

package com.zsh.service.impl;
import java.util.List;
import java.util.Set;
@Service
public class DishServiceImpl implements DishService {
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 新增菜品
     * @param dishDTO
     */
    @Transactional
    @Override
    public void addDish(DishDTO dishDTO) {
        // 创建新增需要用到的对象
        Dish dish = new Dish();
        // 拷贝对象
        BeanUtils.copyProperties(dishDTO,dish);
        // 新增菜品
        dishMapper.addDish(dish);
        // 获取insert语句生成的主键值
        Long dishId = dish.getId();
        // 取出前台传过来的口味表数据
        List<DishFlavor> flavors = dishDTO.getFlavors();
        // 判断前端前台是否添加了口味表数据
        if(flavors != null && flavors.size() > 0){
            flavors.forEach(flavor -> {
                flavor.setDishId(dishId);
            });
        }
        // 新增口味
        dishFlavorMapper.addDishFlavor(flavors);
    }
    /**
     * 菜品分页查询
     * @param dishPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageDish(DishPageQueryDTO dishPageQueryDTO) {
        // 开启分页查询
        PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
        // 条件查询
        List<DishVO> list = dishMapper.pageDish(dishPageQueryDTO);
        // 获取分页结果
        Page page = (Page) list;
        // 封装结果
        PageResult pageResult = new PageResult(page.getTotal(),page.getResult());
        return pageResult;
    }
    /**
     * 根据id查询菜品
     * @param id
     * @return
     */
    @Override
    public DishVO findByIdDish(Integer id) {
        // 查询菜品
        Dish dish = dishMapper.findById(id);
        // 根据菜品id查询口味
        List<DishFlavor> flavors = dishFlavorMapper.findByDishId(id);
        // 封装返回结果
        DishVO dishVO = new DishVO();
        // 拷贝对象
        BeanUtils.copyProperties(dish,dishVO);
        // 给对象的属性赋值
        dishVO.setFlavors(flavors);
        // 返回结果
        return dishVO;
    }
    /**
     * 修改菜品
     * @param dishDTO
     */
    @Override
    @Transactional
    public void updateDish(DishDTO dishDTO) {
        // 创建修改需要用到的对象
        Dish dish = new Dish();
        // 拷贝对象
        BeanUtils.copyProperties(dishDTO,dish);
        // 修改菜品
        dishMapper.updateDish(dish);
        // 删除口味
        dishFlavorMapper.deleteByDishId(dishDTO.getId());
        // 取出修改后的口味数组
        List<DishFlavor> flavors = dishDTO.getFlavors();
        // 判断口味是否修改
        if(flavors != null && flavors.size()>0){
            // 遍历将id放数组
            flavors.forEach(flavor -> {
                flavor.setDishId(dishDTO.getId());
            });
            // 添加新的口味
            dishFlavorMapper.addDishFlavor(flavors);
        }
        //将所有的菜品缓存数据清理掉,所有以dish_开头的key
        cleanCache("dish_*");
    }
    /**
     * 批量删除菜品
     * @param ids
     */
    @Transactional
    @Override
    public void deleteDish(List<Integer> ids) {
        // 判断菜品是否起售,如果起售则不删除
        for (Integer id : ids) {
            // 根据id查询菜品
            Dish dish = dishMapper.findById(id);
            // 判断菜品是否起售
            if (dish.getStatus() == StatusConstant.ENABLE) {
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }
        // TODO这里要判断菜品是否被套餐关联,关联则不能删除
        List<Setmeal> list = setmealDishMapper.findByDishId(ids);
        if(list != null && list.size() > 0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
        for (Integer id : ids) {
            // 删除菜品
            dishMapper.deleteById(id);
            // 删除口味
            dishFlavorMapper.deleteByDishId(Long.valueOf(id));
        }
        // 将所有的菜品缓存数据清理掉,所有以dish_开头的key
        cleanCache("dish_*");
    }
    /**
     * 菜品起售、停售
     * @param status
     * @param id
     */
    @Override
    public void okAndNo(Integer status, Integer id) {
        // 创建修改要用到的对象
        Dish dish = new Dish();
        // 设置状态
        dish.setStatus(status);
        // 设置id
        dish.setId(Long.valueOf(id));
        // 修改
        dishMapper.updateDish(dish);
        // 将所有的菜品缓存数据清理掉,所有以dish_开头的key
        cleanCache("dish_*");
    }
    /**
     * 根据分类id查询菜品
     * @param categoryId
     * @return
     */
    @Override
    public List<DishVO> findByCategoryId(Integer categoryId) {
        // 构造redis中的key,规则dish_分类id
        String key = "dish_"+ categoryId;
        // 查询redis中是否存在菜品数据
        List<DishVO> redisList = (List<DishVO>) redisTemplate.opsForValue().get(key);
        // 判断redis数据库是否存在数据,存在则无序查询mysql
        if(redisList != null && redisList.size() > 0){
            return redisList;
        }
        // 查询MySQL数据库
        List<DishVO> list = dishMapper.findByCategoryId(categoryId);
        // 获取菜品id
        for (DishVO dish : list) {
            // 根据菜品id查询菜品口味
            List<DishFlavor> disFlavor = dishFlavorMapper.findByDishId(Math.toIntExact(dish.getId()));
            // 将口味放入对应的菜品
            dish.setFlavors(disFlavor);
        }
        // 如果redis数据库中没有查到数据,就把查到的数据保存到数据库
        redisTemplate.opsForValue().set(key,list);
        // 返回结果
        return list;
    }
    /**
     * 清理缓存数据
     * @param pattern
     */
    private void cleanCache(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }
}

image.gif

SpringCache

Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

1、 导入Spring Cache和Redis相关maven坐标

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

image.gif

2、在启动类上加入@EnableCaching注解,开启缓存注解功能

package com.zsh;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
@EnableCaching
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}

image.gif

3、在用户端接口SetmealController的 list 方法上加入@Cacheable注解

/**
 * 条件查询
 *
 * @param categoryId
 * @return
 */
@GetMapping("/list")
@ApiOperation("根据分类id查询套餐")
@Cacheable(cacheNames = "setmealCache",key = "#categoryId") //key: setmealCache::100
public Result<List<Setmeal>> list(Long categoryId) {
    Setmeal setmeal = new Setmeal();
    setmeal.setCategoryId(categoryId);
    setmeal.setStatus(StatusConstant.ENABLE);
    List<Setmeal> list = setmealService.list(setmeal);
    return Result.success(list);
}

image.gif

4、在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解

/**
 * 新增套餐
 *
 * @param setmealDTO
 * @return
 */
@PostMapping
@ApiOperation("新增套餐")
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")//key: setmealCache::100
public Result save(@RequestBody SetmealDTO setmealDTO) {
    setmealService.saveWithDish(setmealDTO);
    return Result.success();
}
/**
 * 批量删除套餐
 *
 * @param ids
 * @return
 */
@DeleteMapping
@ApiOperation("批量删除套餐")
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result delete(@RequestParam List<Long> ids) {
    setmealService.deleteBatch(ids);
    return Result.success();
}
/**
 * 修改套餐
 *
 * @param setmealDTO
 * @return
 */
@PutMapping
@ApiOperation("修改套餐")
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result update(@RequestBody SetmealDTO setmealDTO) {
    setmealService.update(setmealDTO);
    return Result.success();
}
/**
 * 套餐起售停售
 *
 * @param status
 * @param id
 * @return
 */
@PostMapping("/status/{status}")
@ApiOperation("套餐起售停售")
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result startOrStop(@PathVariable Integer status, Long id) {
    setmealService.startOrStop(status, id);
    return Result.success();
}

image.gif

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
9天前
|
存储 消息中间件 NoSQL
使用Java操作Redis数据类型的详解指南
通过使用Jedis库,可以在Java中方便地操作Redis的各种数据类型。本文详细介绍了字符串、哈希、列表、集合和有序集合的基本操作及其对应的Java实现。这些示例展示了如何使用Java与Redis进行交互,为开发高效的Redis客户端应用程序提供了基础。希望本文的指南能帮助您更好地理解和使用Redis,提升应用程序的性能和可靠性。
23 1
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
59 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
1月前
|
缓存 NoSQL Java
Java中redis面试题
Java中redis面试题
34 1
|
21天前
|
存储 NoSQL Java
Java 使用 Redis
10月更文挑战第22天
26 0
|
1月前
|
NoSQL Java API
Java操作redis
Java操作redis
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
74 6
|
7天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
9天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构