SpringBoot實(shí)戰(zhàn)—緩存簡(jiǎn)單使用

一.Redis緩存

修改用戶端接口 DishController 的 list 方法,加入緩存處理邏輯:

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 根據(jù)分類id查詢菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根據(jù)分類id查詢菜品")
    public Result<List<DishVO>> list(Long categoryId) {

        //構(gòu)造redis中的key,規(guī)則:dish_分類id
        String key = "dish_" + categoryId;

        //查詢r(jià)edis中是否存在菜品數(shù)據(jù)
        List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);
        if(list != null && list.size() > 0){
            //如果存在,直接返回,無(wú)須查詢數(shù)據(jù)庫(kù)
            return Result.success(list);
        }
        ////////////////////////////////////////////////////////
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);//查詢起售中的菜品

        //如果不存在,查詢數(shù)據(jù)庫(kù),將查詢到的數(shù)據(jù)放入redis中
        list = dishService.listWithFlavor(dish);
        ////////////////////////////////////////////////////////
        redisTemplate.opsForValue().set(key, list);

        return Result.success(list);
    }

為了保證數(shù)據(jù)庫(kù)Redis中的數(shù)據(jù)保持一致,修改管理端接口 DishController 的相關(guān)方法,加入清理緩存邏輯。

需要改造的方法:

  • 新增菜品
  • 修改菜品
  • 批量刪除菜品
  • 起售、停售菜品

抽取清理緩存的方法:
在管理端DishController中添加

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 清理緩存數(shù)據(jù)
     * @param pattern
     */
    private void cleanCache(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

調(diào)用清理緩存的方法,保證數(shù)據(jù)一致性:
1). 新增菜品優(yōu)化

    /**
     * 新增菜品
     *
     * @param dishDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品")
    public Result save(@RequestBody DishDTO dishDTO) {
        log.info("新增菜品:{}", dishDTO);
        dishService.saveWithFlavor(dishDTO);

        //清理緩存數(shù)據(jù)
        String key = "dish_" + dishDTO.getCategoryId();
        cleanCache(key);
        return Result.success();
    }

2). 菜品批量刪除優(yōu)化

    /**
     * 菜品批量刪除
     *
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("菜品批量刪除")
    public Result delete(@RequestParam List<Long> ids) {
        log.info("菜品批量刪除:{}", ids);
        dishService.deleteBatch(ids);

        //將所有的菜品緩存數(shù)據(jù)清理掉,所有以dish_開(kāi)頭的key
        cleanCache("dish_*");

        return Result.success();
    }

**3). 修改菜品優(yōu)化 **

    /**
     * 修改菜品
     *
     * @param dishDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改菜品")
    public Result update(@RequestBody DishDTO dishDTO) {
        log.info("修改菜品:{}", dishDTO);
        dishService.updateWithFlavor(dishDTO);

        //將所有的菜品緩存數(shù)據(jù)清理掉,所有以dish_開(kāi)頭的key
        cleanCache("dish_*");

        return Result.success();
    }

4). 菜品起售停售優(yōu)化

    /**
     * 菜品起售停售
     *
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("菜品起售停售")
    public Result<String> startOrStop(@PathVariable Integer status, Long id) {
        dishService.startOrStop(status, id);

        //將所有的菜品緩存數(shù)據(jù)清理掉,所有以dish_開(kāi)頭的key
        cleanCache("dish_*");

        return Result.success();
    }

二、Spring Cache

Spring Cache 是一個(gè)框架,實(shí)現(xiàn)了基于注解的緩存功能,只需要簡(jiǎn)單地加一個(gè)注解,就能實(shí)現(xiàn)緩存功能。
提供了一層抽象,底層可以切換不同的緩存實(shí)現(xiàn),例如:

  • EHCache
  • Caffeine
  • Redis(常用)

起步依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>                                       <version>2.7.3</version> 
</dependency>

在SpringCache中提供了很多緩存操作的注解,常見(jiàn)的是以下的幾個(gè):

注解 說(shuō)明
@EnableCaching 開(kāi)啟緩存注解功能,通常加在啟動(dòng)類上
@Cacheable 在方法執(zhí)行前先查詢緩存中是否有數(shù)據(jù),如果有數(shù)據(jù),則直接返回緩存數(shù)據(jù);如果沒(méi)有緩存數(shù)據(jù),調(diào)用方法并將方法返回值放到緩存中
@CachePut 將方法的返回值放到緩存中
@CacheEvict 將一條或多條數(shù)據(jù)從緩存中刪除

在spring boot項(xiàng)目中,使用緩存技術(shù)只需在項(xiàng)目中導(dǎo)入相關(guān)緩存技術(shù)的依賴包,并在啟動(dòng)類上使用@EnableCaching開(kāi)啟緩存支持即可。

例如,使用Redis作為緩存技術(shù),只需要導(dǎo)入Spring data Redis的maven坐標(biāo)即可。

1)引導(dǎo)類上加@EnableCaching:

package com.itheima;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@Slf4j
@SpringBootApplication
@EnableCaching//開(kāi)啟緩存注解功能
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("項(xiàng)目啟動(dòng)成功...");
    }
}

2). @CachePut注解

@CachePut 說(shuō)明:
作用: 將方法返回值,放入緩存
value: 緩存的名稱, 每個(gè)緩存名稱下面可以有很多key
key: 緩存的key ----------> 支持Spring的表達(dá)式語(yǔ)言SPEL語(yǔ)法

在save方法上加注解@CachePut
當(dāng)前UserController的save方法是用來(lái)保存用戶信息的,我們希望在該用戶信息保存到數(shù)據(jù)庫(kù)的同時(shí),也往緩存中緩存一份數(shù)據(jù),我們可以在save方法上加上注解 @CachePut,用法如下:

/**
    * CachePut:將方法返回值放入緩存
    * value:緩存的名稱,每個(gè)緩存名稱下面可以有多個(gè)key
    * key:緩存的key
    */
    @PostMapping
    @CachePut(value = "userCache", key = "#user.id")//key的生成:userCache::1
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

說(shuō)明:key的寫(xiě)法如下
#user.id : #user指的是方法形參的名稱, id指的是user的id屬性 , 也就是使用user的id屬性作為key ;
#result.id: #result代表方法返回值,該表達(dá)式 代表以返回對(duì)象的id屬性作為key ;
#p0.id:#p0指的是方法中的第一個(gè)參數(shù),id指的是第一個(gè)參數(shù)的id屬性,也就是使用第一個(gè)參數(shù)的id屬性作為key ;
#a0.id:#a0指的是方法中的第一個(gè)參數(shù),id指的是第一個(gè)參數(shù)的id屬性,也就是使用第一個(gè)參數(shù)的id屬性作為key ;
#root.args[0].id:#root.args[0]指的是方法中的第一個(gè)參數(shù),id指的是第一個(gè)參數(shù)的id屬性,也就是使用第一個(gè)參數(shù)的id屬性作為key ;
啟動(dòng)服務(wù),通過(guò)swagger接口文檔測(cè)試,訪問(wèn)UserController的save()方法
因?yàn)閕d是自增,所以不需要設(shè)置id屬性

3). @Cacheable注解
@Cacheable 說(shuō)明:
作用: 在方法執(zhí)行前,spring先查看緩存中是否有數(shù)據(jù),如果有數(shù)據(jù),則直接返回緩存數(shù)據(jù);若沒(méi)有數(shù)據(jù),調(diào)用方法并將方法返回值放到緩存中
value: 緩存的名稱,每個(gè)緩存名稱下面可以有多個(gè)key
key: 緩存的key ----------> 支持Spring的表達(dá)式語(yǔ)言SPEL語(yǔ)法

在getById上加注解@Cacheable

    @GetMapping
    @Cacheable(cacheNames = "userCache",key="#id")
    public User getById(Long id){
        User user = userMapper.getById(id);
        return user;
    }

4). @CacheEvict注解
@CacheEvict 說(shuō)明:
作用: 清理指定緩存
value: 緩存的名稱,每個(gè)緩存名稱下面可以有多個(gè)key
key: 緩存的key ----------> 支持Spring的表達(dá)式語(yǔ)言SPEL語(yǔ)法

在 delete 方法上加注解@CacheEvict

@DeleteMapping
    @CacheEvict(cacheNames = "userCache",key = "#id")//刪除某個(gè)key對(duì)應(yīng)的緩存數(shù)據(jù)
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }

    @DeleteMapping("/delAll")
    @CacheEvict(cacheNames = "userCache",allEntries = true)//刪除userCache下所有的緩存數(shù)據(jù)
    public void deleteAll(){
        userMapper.deleteAll();
    }

項(xiàng)目使用

1). 導(dǎo)入Spring Cache和Redis相關(guān)maven坐標(biāo)(已實(shí)現(xiàn))

<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>

2). 在啟動(dòng)類上加入@EnableCaching注解,開(kāi)啟緩存注解功能

package com.sky;

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 //開(kāi)啟注解方式的事務(wù)管理
@Slf4j
@EnableCaching
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}

3). 在用戶端接口SetmealController的 list 方法上加入@Cacheable注解

    /**
     * 條件查詢
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根據(jù)分類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);
    }

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();
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容