一、緩存機制的原理 一個系統在面向用戶使用的時候,當用戶的數量不斷增多,那麼請求次數也會不斷增多,當請求次數增多的時候,就會造成請求壓力,而我們當前的所有數據查詢都是從資料庫MySQL中直接查詢的,那麼就可能會產生如下問題 ==頻繁訪問資料庫,資料庫訪問壓力大,系統性能下降,用戶體驗差== 解決問題 ...
一、緩存機制的原理
- 一個系統在面向用戶使用的時候,當用戶的數量不斷增多,那麼請求次數也會不斷增多,當請求次數增多的時候,就會造成請求壓力,而我們當前的所有數據查詢都是從資料庫MySQL中直接查詢的,那麼就可能會產生如下問題
- 頻繁訪問資料庫,資料庫訪問壓力大,系統性能下降,用戶體驗差
- 解決問題的方法
- 要解決上述提到的問題,就可以使用前面學習的Redis技術,通過Redis實現緩存機制,從而降低資料庫的訪問壓力;提高系統的訪問性能,從而提升用戶體驗
- 加入Redis後,在進行數據查詢的時候,就需要先查詢緩存,如果緩存中有數據,直接返回;如果沒有相對應的數據,那麼就去查詢資料庫,再將資料庫查詢的結果,緩存在Redis中
二、緩存簡訊驗證碼
環境搭建
①、在項目pom.xml文件中導入spring-data-redis的maven坐標
<!--Spring data redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
②、在項目的配置文件中加入Redis相關配置(在Spring層級下)
redis: jedis: pool: max-idle: 5 #最大鏈接數,連接池中最多有10個 min-idle: 1 # 最大空閑數 max-wait: 1000ms #連接池最大阻塞等待時間 max-active: 10 #最大鏈接數 host: 127.0.0.1 port: 6379 database: 2 # password:
2.1、思路分析
- 前面實現的移動端手機驗證登錄功能,隨機生成的驗證碼是保存在
HttpSession
當中的。但是實際的業務場景中,一般驗證碼都是需要設置過期時間的,如果存在HttpSession
中就無法設置過期時間,此時我們就需要對這一塊的功能進行優化 - 可以將驗證碼緩存在Redis中,具體的實現思路如下
- ①、在服務端
UserController
中註入RedisTemplate
對象,用於操作Redis - ②、在服務端
UserController
的sendMsg
方法中,將隨機生成的驗證碼緩存到Redis中,並設置有效期為5分組 - ③、在服務端
UserController
的login
方法中,從Redis中獲取緩存的驗證碼,如果登錄成功則刪除Redis中的驗證碼
- ①、在服務端
2.2、代碼改造
-
①、在
UserController
中註入RedisTemplate
對象,用於操作Redis-
@Autowired private RedisTemplate<String, String> redisTemplate;
-
-
②、在
UserController
的sendMsg
方法中,將生成的驗證碼保存到Redis中(為了測試方便,這裡是直接生成了固定的驗證碼,沒有調用真實的生成驗證碼的API)-
// 將登錄賬號的信息存儲在redis中 // 獲取字元串的客戶端 ValueOperations<String, String> valueOperations = redisTemplate.opsForValue(); // 存儲驗證碼,讓驗證碼失效時間是一分鐘 valueOperations.set("SMS_" + user.getPhone(), code, 1, TimeUnit.MINUTES);
-
-
③、在登錄校驗的代碼中實現從Redis中取出數據
-
// 2. 獲取正確的驗證碼 // String verifyCode = (String) session.getAttribute("SMS_" + inputPhone); // 從redis中獲取正確的驗證碼 String verifyCode = redisTemplate.opsForValue().get("SMS_" + inputPhone);
-
2.3、功能測試
- ①、訪問前端,獲取驗證碼
- 通過控制台的日誌,可以看到生成的代碼
- ②、通過Redis的圖形化界面工具查看Redis中的數據
- ③、在登錄界面填寫驗證碼登錄完成後,查看Redis中的數據是否刪除
三、緩存菜品信息
3.1、思路分析
-
之前項目中已經實現了移動端菜品查看的功能,對應的服務端方法為
DishController
的list
方法,此方法會根據前端提交的查詢條件(categoryId
)進行資料庫查詢操作。 -
在高併發的情況下,頻繁查詢資料庫會導致系統性能下降,服務端響應時間增長;針對這個問題,可以對此方法進行緩存優化,提高系統的性能
-
那麼應該緩存多少分數據呢?是所有的菜品緩存一份,還是需要根據分類的不同,緩存多份?
- 很顯然,在前端點擊一個分類的時候,展示的就是這個分類下的菜品,其他菜品無需展示
- 所以,這裡面我們在緩存時,可以根據菜品的分類,緩存多分數據,頁面在提交查詢請求的時候,就查詢該分類下的菜品緩存數據
-
具體實現思路
- ①、修改業務層的
list
方法,先從Redis中獲取分類對應的菜品數據,如果有則直接返回,無需查詢資料庫;如果沒有,則查詢資料庫,並將查詢到的菜品數據存入Redis - ②、修改
DishController
的save
和update
方法,加入清理緩存的邏輯
- ①、修改業務層的
-
註意事項
- 在使用緩存的過程當中,要註意保證資料庫中的數據和緩存中的數據保持一致
- 如果資料庫中的數據發生變化,需要及時清理緩存數據。否則就會造成緩存數據與資料庫數據不一致的情況
3.2、代碼改造
3.2.1、查詢菜品緩存
在增加緩存之前,需要對存儲進Redis中的數據進行一個簡單的設計,如下所示
數據類型 key值 value值 String dish_菜品分類的id 菜品的List集合(List )
-
①、在
DishServiceImpl
中註入RedisTemplate
-
@Autowired private RedisTemplate<String, String> redisTemplate;
-
-
②、在
list
方法中,查詢資料庫之前,先查詢緩存,如果緩存有數據,則直接返回-
// 根據分類id查詢菜品列表數據 @Override public List<DishDto> selectByCategoryIdAndStatus(Long categoryId, Integer status) { // 0. 首先先判斷Redis中是否存在緩存 // 獲取redis操作字元串的客戶端 ValueOperations<String, String> valueOperations = redisTemplate.opsForValue(); List<DishDto> dishDtoList = JSON.parseObject(valueOperations.get("dish_" + categoryId + "_" + status), List.class); // 如果redis中不存在這個緩存,則查詢資料庫,並且將查詢到的結果存儲到緩存中 if (dishDtoList == null) { // 1. 調用 dao 層對象執行sql語句查詢數據 List<Dish> dishList = dishMapper.selectByCategoryIdAndStatus(categoryId, status); // 2. 遍歷dishList,查詢其相對應的口味數據表 dishDtoList = dishList.stream().map(dish -> { // 查詢對應的口味表 List<DishFlavor> dishFlavorList = dishFlavorMapper.selectByDishId(dish.getId()); DishDto dishDto = new DishDto(); // 將數據封裝到dishDto中 dishDto.setFlavors(dishFlavorList); // 將基本屬性複製給dishDto BeanUtils.copyProperties(dish, dishDto); return dishDto; }).collect(Collectors.toList()); // 把查詢到的數據,存儲到Redis中 // 把dishDtoList對象轉換為Json格式 String dishJson = JSON.toJSONString(dishDtoList); valueOperations.set("dish_" + categoryId, dishJson, 2, TimeUnit.DAYS); } // 返回數據 return dishDtoList; }
-
3.2.2、清理菜品緩存
為了保證資料庫中的數據和緩存中的數據一致,如果資料庫中的數據發生變化,需要及時清理緩存數據
所以,需要在菜品的增刪改中清空緩存數據
-
清理菜品緩存的方式有兩種
-
A、清理所有分類下的菜品緩存
-
//清理所有菜品的緩存數據 Set keys = redisTemplhate.keys("dish_*"); //獲取所有以dish_xxx開頭的key redisTemplate.delete(keys); //刪除這些key
-
-
B、清理當前添加菜品分類下的緩存
-
//清理某個分類下麵的菜品緩存數據 String key = "dish_" + dishDto.getCategoryId(); redisTemplate.delete(key);
-
-
兩者的優劣(需要結合實際的業務場景考慮)
- 對於這次的修改操作,用戶可以修改菜品的分類,如果用戶修改了了菜品的分類,那麼原來的分類下將少一個菜品,新的分類下將多一個菜品,這樣的話,兩個分類的菜品列表數據都發生了變化
- 即此時的情況不能只是刪除某一個分類的菜品緩存
- 所以,在本次的系統中推薦使用第一種方法清理菜品緩存
-
-
這裡清理緩存的操作比較簡單,就不演示了,只需要在數據發生變更後的代碼後面添加一個刪除緩存的代碼即可,如下所示
3.3、功能測試
- ①、訪問移動端,根據分類查詢菜品列表,然後再檢查Redis的緩存數據是否存在
- ②、當對菜品進行增刪改的時候,查詢Redis中的緩存數據,是否被清除
四、Spring Cache
4.1、Spring Cache介紹
-
Spring Cache是一個框架,實現了基於註解的緩存功能,只需要簡單地加一個註解,就能實現緩存功能,大大簡化我們在業務中操作緩存的代碼
-
Spring Cache只是提供了一層抽象,底層可以切換不同的cache實現。具體就是通過CacheManager介面來統一不同的緩存技術。CacheManager是Spring提供的各種緩存技術抽象介面
-
針對不同的緩存技術需要實現不同的CacheManager,如下表所示
-
CacheManager 描述 EhCacheCacheManager 使用EhCache作為緩存技術 GuavaCacheManager 使用Google的GuavaCache作為緩存技術 RedisCacheManager 使用Redis作為緩存技術 spring 自己也搞了一套緩存技術,預設的緩存
spring緩存是緩存在Map集合中
-
4.2、Spring Cache註解
-
在SpringCache中提供了很多緩存操作的註解,常見的幾個如下所示
-
註解 說明 @EnableCaching 開啟緩存註解功能 @Cacheable 在方法執行前Spring先查看緩存中是否有數據,如果有數據,則直接返回緩存數據;若沒有數據,則調用方法並將方法返回值放到緩存中 @CachePut 將方法的返回值或者參數放到緩存中 @CacheEvict 將一條或多條數據從緩存中刪除
-
-
在SpringBoot項目中,使用緩存技術只需在項目中導入相關緩存技術的依賴包,併在啟動類上使用@EnableCaching開啟緩存支持即可
- 例如使用Redis作為緩存技術,只需要導入Spring data Redis的maven坐標,同時在配置文件中配置Redis的相關配置即可
4.3、Spring Cache入門案例
- 接下來,我們可以通過一個入門案例演示以下SpringCache的常見用法。上面提到,SpringCache可以集成不同的緩存技術,如Redis、Ehcache甚至我們可以使用Map來緩存數據,接下來我們在演示的時候,就先通過一個Map來緩存數據,最後我們再換成Redis來緩存
4.3.1、環境準備
-
①、資料庫準備
-
/* SQLyog Ultimate v11.33 (64 bit) MySQL - 5.5.40 : Database - cache_demo ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; CREATE DATABASE /*!32312 IF NOT EXISTS*/`cache_demo` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `cache_demo`; /*Table structure for table `user` */ DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `address` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; /*Data for the table `user` */ LOCK TABLES `user` WRITE; UNLOCK TABLES; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
-
②、導入基本工程
- 基本工程的創建,這裡就不演示了,只是一個User表的增刪改查操作
-
③、註入CacheManager
- 我們可以在
UserController
註入一個CacheManager
,在Debug時,我們可以通過CacheManger
跟蹤緩存中數據的變化 - 我們可以進入CacheManger介面的源碼中查看,預設的實現有幾種,如下圖所示
- 而在上述的幾個實現中,預設使用的是
ConcurrentMapCacheManger
,稍後我們可以通過斷點的形式跟蹤緩存數據的變化
- 我們可以在
-
④、啟動類加上@EnableCaching註解
- 在啟動類加上該註解,就代表當前項目開啟緩存註解功能
4.3.2、@CachePut註解
- @CachePut註解說明
- 作用
- 將方法返回值,放入緩存
- value
- 緩存的名稱,每個緩存名稱下麵可以有很多key
- key
- 緩存的key,支持Spring的表達式語言SPEL語法
-
①、在save方法上加上註解@CachePut
-
當前
UserController
的save
方法是用來保存用戶信息的,我們希望在該用戶信息保存到資料庫的同時,也往緩存中緩存一份數據,我們可以在save
方法上加上註解@CachePut
,如下所示 -
/** * CachePut:將方法返回值放入緩存 * value:緩存的名稱,每個緩存名稱下麵可以有多個key * key:緩存的key */ @CachePut(value = "userCache", key = "#user.id") @PostMapping public User save(@RequestBody User user){ userService.save(user); return user; }
-
key的寫法如下:
#user.id
#user
指的是方法形參的名稱, id指的是user的id屬性 , 也就是使用user的id屬性作為key
#user.name
#user
指的是方法形參的名稱, name指的是user的name屬性 ,也就是使用user的name屬性作為key
#result.id
#result
代表方法返回值,該表達式 代表以返回對象的id屬性作為key
#result.name
#result
代表方法返回值,該表達式 代表以返回對象的name屬性作為key
-
-
②、使用Postman進行功能測試
- 啟動服務,通過postman請求訪問
UserController
的方法, 然後通過斷點(Debug)的形式跟蹤緩存數據 - 第一次訪問時,緩存中的數據是空的,因為save方法執行完畢後才會緩存數據
- 第二次訪問時,我們通過debug可以看到已經有一條數據了,就是上次保存的數據,已經緩存了,緩存的key就是用戶的id
- 啟動服務,通過postman請求訪問
-
PS
- 上述的演示,最終的數據,實際上是緩存在ConcurrentHashMap中,那麼當我們的伺服器重啟之後,緩存中的數據就會丟失。 後面使用了Redis來緩存就不存在這樣的問題
4.3.3、@CacheEvict註解
- @CacheEvict註解說明
- 作用
- 清理指定緩存
- value
- 緩存的名稱,每個緩存名稱下麵可以有多個key
- key
- 緩存的key,支持Spring的表達式語言SPEL語法
-
①、在delete方法上加@CacheEvict註解
-
當我們在刪除資料庫
user
表數據的時候,需要刪除緩存中對應的數據,此時就可以使用@CacheEvict
註解,如下所示-
/** * CacheEvict:清理指定緩存 * value:緩存的名稱,每個緩存名稱下麵可以有多個key * key:緩存的key */ @CacheEvict(value = "userCache", key = "#p0") //#p0 代表第一個參數 //@CacheEvict(value = "userCache",key = "#root.args[0]") //#root.args[0] 代表第一個參數 //@CacheEvict(value = "userCache",key = "#id") //#id 代表變數名為id的參數 @DeleteMapping("/{id}") public void delete(@PathVariable Long id){ userService.removeById(id); }
-
-
-
②、使用Postman進行功能測試
- 測試緩存的刪除,先訪問save方法任意次,保存n條數據到資料庫的同時,也保存到緩存中,最終可以通過debug看到緩存中的數據信息,然後可以通過Postman方法delete方法,進行緩存的刪除
- 刪除數據的時候,通過debug可以看到已經緩存的4條數據
- 當執行完delete操作後,我們再保存一條數據,在保存的時候debug查看之前的緩存是否已經被刪除
-
③、在update方法上加註解@CacheEvict
-
在更新數據之後,資料庫的數據已經發生了變更,我們需要將緩存中對應的數據刪除掉,避免出現資料庫數據與緩存數據不一致的情況
-
//@CacheEvict(value = "userCache",key = "#p0.id") //第一個參數的id屬性 //@CacheEvict(value = "userCache",key = "#user.id") //參數名為user參數的id屬性 //@CacheEvict(value = "userCache",key = "#root.args[0].id") //第一個參數的id屬性 @CacheEvict(value = "userCache",key = "#result.id") //返回值的id屬性 @PutMapping public User update(@RequestBody User user){ userService.updateById(user); return user; }
-
-
加上註解之後,重啟服務,然後使用Postman進行測試,測試步驟和方法跟上述①、②差不多,這裡就不再演示
-
4.3.4、@Cacheable註解
- @Cacheable註解說明
- 作用
- 在方法執行前,Spring先查看緩存中是否有數據,如果有數據,則直接返回緩存數據;若沒有數據,調用方法並將方法返回值放入到緩存中
- value
- 緩存的名稱,每個緩存名稱下麵可以有多個key
- key
- 緩存的key,支持Spring的表達式語言SPEL語法
-
①、在getById方法上加@Cacheable註解
-
@Cacheable(value = "user",key = "#id") @GetMapping("/{id}") public User getById(@PathVariable Long id){ User user = userService.findById(id); return user; }
-
-
②、使用Postman進行功能測試
- 重啟服務,然後通過debug斷點跟蹤程式執行;可以發現,第一次訪問,會請求
Controller
的方法,查詢資料庫。後面再查詢相同的id,就直接獲取到資料庫,不用再查詢資料庫了,就說明緩存已經生效- 第一次查詢
- 第二次查詢
- 第一次查詢
- 在測試的時候,查詢一個資料庫中不存在的id值,第一次查詢緩存中沒有,也會查詢資料庫。第二次查詢的時候,會發現,不再查詢資料庫了,而是直接返回,那也就是說如果根據id沒有查詢到數據,那麼會自動緩存一個null值,可以通過debug進行驗證一下
- 第一次查詢
- 第二次查詢
- 第一次查詢
- 這時候就會出現一個問題,能不能查詢到的值不為null值的時候再進行緩存,如果為null值,則不進行緩存呢?
- 重啟服務,然後通過debug斷點跟蹤程式執行;可以發現,第一次訪問,會請求
-
③、緩存非null值
-
在
@Cacheable
註解中,提供了兩個屬性分別為:condition
、unless
condition
- 表示滿足什麼條件,再進行緩存
unless
- 表示滿足條件則不緩存,與上述的condition是反向的
-
具體實現方法如下所示
-
/** * 註意: @Cacheable把方法的返回值緩存起來, 即使方法返回值為null也會被緩存,如果需要改變這個結果: * condition : 符合指定條件則緩存,這個屬性不建議使用,因為condition這個屬性不能使用result。 * unless : 不符合指定條件則緩存 */ // @Cacheable 執行方法前先判斷緩存是否存在指定id的user, // 如果存在不會執行方法,直接返回緩存中數據即可。如果不存在才會返回緩存數據 @Cacheable(value = "user",key = "#id",unless = "#result==null") @GetMapping("/{id}") public User getById(@PathVariable Long id){ User user = userService.findById(id); return user; }
-
-
這裡這能使用
unless
,因為condition
屬性無法獲取到結果#result
-
4.4.、Spring Cache集成Redis
-
在使用上述預設的ConcurrentHashMap做緩存時,服務重啟之後,之前緩存的數據就全部丟失了,操作起來並不友好。在項目中使用,我們會選擇使用redis來做緩存,主要需要操作以下幾步
-
①、添加依賴
-
<!--spring cache依賴導入--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!--spring data redis 導入--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
-
②、配置application.yaml配置文件(Spring層級下)
-
redis: host: 127.0.0.1 database: 2 cache: redis: time-to-live: 1800000 #單位毫秒,設置緩存過期時間,可選
-
-
③、測試
-
五、緩存套餐數據
5.1、思路分析
- 前面已經實現了移動端套餐查看功能,對應的服務端方法為
SetmealController
的list方法,此方法會根據前端提交的查詢條件進行資料庫查詢操作 - 在高併發的情況下,頻繁地查詢資料庫會導致系統性能下降,服務端響應時間增長。現在需要對此方法進行緩存優化,提高系統的性能
5.2、代碼改造
-
①、導入SpringCache和Redis相關的maven坐標(spring data redis之前已經導入過了)
-
<!--spring cache依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
-
-
②、在application.yml配置文件中配置緩存數據的過期時間
-
cache: redis: time-to-live: 1800000 # 設置緩存數據過期時間
-
-
③、在啟動類上加入@EnableCaching註解,開啟緩存註解功能
-
package com.coolman; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cache.annotation.EnableCaching; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @MapperScan(basePackages = "com.coolman.mapper") @ServletComponentScan(basePackages = "com.coolman.filters") @EnableTransactionManagement //開啟對事務管理的支持 @EnableCaching public class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class, args); } }
-
-
④、在
SetmealServiceImpl
的selectByCategoryIdAndStatus
方法上加入@Cacheable註解-
在進行套餐數據查詢時,需要根據分類ID和套餐的狀態進行查詢,所以在緩存數據的時候,可以將套餐分類id和套餐狀態組合起來作為key,如下所示
1627182182_1
(1627182182是分類id,1是狀態)
-
@Override @Cacheable(value = "setmeal", key = "#categoryId + '_' + #status") public List<SetMeal> selectByCategoryIdAndStatus(Long categoryId, Integer status) { return setMealMapper.selectByCategoryIdAndStatus(categoryId, status); }
-
-
⑤、在
SetmealServiceImpl
的數據變更方法上加入@CacheEvict註解-
為了保證資料庫中數據與緩存數據的一致性,在添加套餐或者刪除套餐數據之後,需要清空當前套餐緩存的全部數據
-
那麼@CacheEvict註解如何清除某一份緩存下所有的數據呢?這裡可以指定@CacheEvict中的一個屬性allEnties,將其設置為true即可,其含義為setmeal名稱空間下麵的所有key都刪除
-
@CacheEvict(value = "setmeal", allEntries = true) // allEntries = true 代表了setmeal名稱空間下麵的所有key都刪除 public void update(SetMealDto setMealDto) { // 補全數據,更新時間 setMealDto.setUpdateTime(LocalDateTime.now()); // 更新setmeal表的數據 setMealMapper.updateByIds(setMealDto, new Long[]{setMealDto.getId()}); // 更新setmeal_dish表的數據 // 先刪除,再修改 // 原因: 前端返回的數據是一個集合,有多個id,同時其中的數據也不是固定不變的,且是一對多關係,處理起來非常麻煩 // 給setmeal_dish補全數據 List<SetMealDish> setmealDishes = setMealDto.getSetmealDishes(); for (SetMealDish setmealDish : setmealDishes) { // 設置創建人和創建時間 setmealDish.setCreateUser(setMealDto.getCreateUser()); setmealDish.setCreateTime(setMealDto.getCreateTime()); // 設置更新時間和更新人 setmealDish.setUpdateUser(setMealDto.getUpdateUser()); setmealDish.setUpdateTime(LocalDateTime.now()); // 設置setmeal_id setmealDish.setSetmealId(setMealDto.getId().toString()); // 設置sort setmealDish.setSort(0); } // 根據id批量刪除數據 ArrayList<String> ids = new ArrayList<>(); ids.add(setMealDto.getId().toString()); setMealDishMapper.deleteByIds(ids); // 批量插入數據 setMealDishMapper.batchInsert(setmealDishes); }
-
上述代碼只是修改功能的一個方法,其他有數據變更的操作,一般都要清理緩存,以保證資料庫的數據和緩存的數據一致
-
5.3、功能測試
- 代碼編寫完成之後,重啟工程,然後訪問後臺管理系統,對套餐數據進行新增以及刪除, 然後通過Redis的圖形化界面工具,查看Redis中的套餐緩存是否已經被刪除
- ①、第一次查詢套餐列表,查看Redis中是否存儲相對應的數據
- ②、第二次查詢套餐列表,查看服務端終端輸出的是否有SQL語句,驗證是否是從Redis中讀取數據
- ③、執行數據變更操作(這裡測試使用添加功能),查看Redis中的緩存數據是否刪除
- 這裡有部分dish值出現null字元的原因是之前在沒單純使用
RedisTemplate
對象的時候沒有刪除測試代碼,所以不管傳入的status值是否為null值,其都會存儲到緩存中,不過在這裡無傷大雅,僅作為測試,在實際應用場景中,非常不建議同時使用RedisTemplate
和Spring redis data
- 這裡有部分dish值出現null字元的原因是之前在沒單純使用
- 到這裡,項目的緩存優化結束!