Java中操作Redis & SpringCache

简介: 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

相关文章
|
9月前
|
存储 SQL NoSQL
Redis-常用语法以及java互联实践案例
本文详细介绍了Redis的数据结构、常用命令及其Java客户端的使用,涵盖String、Hash、List、Set、SortedSet等数据类型及操作,同时提供了Jedis和Spring Boot Data Redis的实战示例,帮助开发者快速掌握Redis在实际项目中的应用。
680 1
Redis-常用语法以及java互联实践案例
|
12月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
625 42
|
12月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
622 6
|
NoSQL Java API
在Java环境下如何进行Redis数据库的操作
总的来说,使用Jedis在Java环境下进行Redis数据库的操作,是一种简单而高效的方法。只需要几行代码,就可以实现复杂的数据操作。同时,Jedis的API设计得非常直观,即使是初学者,也可以快速上手。
471 94
|
Linux 网络安全 Docker
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
尼恩提供了一系列文章,旨在帮助开发者轻松搭建一键开发环境,涵盖Java分布式、高并发场景下的多种技术组件安装与配置。内容包括但不限于Windows和CentOS虚拟机的安装与排坑指南、MySQL、Kafka、Redis、Zookeeper等关键组件在Linux环境下的部署教程,并附带详细的视频指导。此外,还特别介绍了Vagrant这一虚拟环境部署工具,
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
|
Java Android开发
WSDL2Java操作指南
1. 安装JDK1.5, 配置系统环境变量:     下载安装JDK后, 设置环境变量:     JAVA_HOME=C:\Program Files\Java\jdk1.5.0_02     Path=%Path%;%JAVA_HOME%\bin(这里的%Path%指你系统已经有的一系列配置)     CLASSPATH=%JAVA_HOME%\lib  2. 下载axis,
1598 0
|
8月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
403 1
|
8月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
377 1
|
9月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
372 0