springboot-cache的简单使用
springboot-cache 的簡單使用
springboot-cache介紹
一、前言
Spring Cache 對 Cahce 進行了抽象,提供了 @Cacheable、@CachePut、@CacheEvict 等注解。Spring Boot 應用基于 Spring Cache,既提供了基于內存實現的緩存管理器,可以用于單體應用系統,也集成了 Redis 等緩存服務器,可以用于大型系統或者分布式系統。
二、關于 Cache
應用系統需要通過 Cache 來緩存不經常改變的數據以提高系統性能和增加系統吞吐量,避免直接訪問數據庫等低速的存儲系統。緩存的數據通常存放在訪問速度更快的內存中或者是低延遲存取的存儲器、服務器上。緩存系統存儲大都是不經常改變的業務數據,如用戶權限、字典數據、配置信息等等。
springboot-cache的注解講解
1、@Cacheable注解
@Cacheable注解的作用是Spring在調用該方法之前,首先在緩存中查找方法的返回值,默認的key是根據參數值生成,如果存在,直接返回緩存中的值,否則執行該方法,并將返回值保存到緩存中
@Cacheable運行流程:
1.方法運行之前,先去查詢Cache(緩存組件),按照cacheNames指定的名字獲取;
? (CacheManager先獲取相應的緩存),第一次獲取緩存如果沒有Cache組件會自動創建。
2.去Cache中查找緩存的內容,使用一個key,默認就是方法的參數值;
-
? key是按照某種策略生成的;默認是使用keyGenerator生成的,
-
Spring默認加載的是SimpleCacheManage,SimpleKeyGenerator生成key的默認策略是:
-
? 如果沒有參數;key=new SimpleKey()
-
? 如果有一個參數:key=參數的值
-
? 如果有多個參數:key=new SimpleKey(params)
3.沒有查到緩存就調用目標方法;
4.將目標方法返回的結果,放進緩存中
@Cacheable屬性說明:
1.acheNames/value:該屬性值必須提供,指定緩存組件的名字,將方法的返回結果放在哪個緩存中,是數組的 方式,可以指定多個緩存;
如:cacheNames = "product"或者cacheNames = {“product1”,“product2”}
2.key:緩存數據使用的key,不指定key則默認是使用方法參數的值該屬性值支持SpEL表達式
3.cacheManager:指定緩存管理器;或者cacheResolver指定獲取解析器
4.condition:指定符合條件的情況下才緩存 condition = “#a0=1” 當方法中第一個參數=1的時候才進行緩存
5.unless:否定緩存;當unless指定的條件為true,方法的返回值就不會被緩存;可以獲取到結果進行判斷
? unless = “#result == null”
? unless = “#a0==2”:如果第一個參數的值是2,結果不緩存;
6.sync:是否使用異步模式
使用樣例:
/** @Author crush* 原理:* 運行流程:* @Cacheable* 1 方法執行之前 先去查詢Cache (緩存組件) 按照cacheNames 指定的名字獲取* 先去獲取相應的緩存 第一次獲取緩存如果沒有 Cache組件會自動創建* 2 去Cache 中查找緩存的內容 使用一個key 默認就是方法的參數* 3 沒有查到就返回結果* 4 將目標方法返回的結果 放進緩存中** @Cacheable 標注的方法 執行之前 先來檢查緩存中有沒有這個數據 默認按照參數的值作為key去查詢緩存* 如果沒有就運行方法并將結果放入緩存* 屬性:* cacheNames :指定緩存組的名字* key:緩存數據用的key* keyGenerator : 也可以用這個自定義key的值* condition: 指定符合條件下菜緩存 condition="#id>0"* // #a0> 1 表示第一個參數大與1* unless:否定緩存* unless="#a0==2" 如果第一個參數是2 就不緩存* sync:是否使用異步模式**/@Cacheable(cacheNames = "userInfo",key = "#user_id",condition = "#id=1") // #a0> 1 表示第一個參數大與1public UserInfo selectByUserId(String user_id) {System.out.println("根據id查詢用戶");return userInfoMapper.selectByUserId(user_id);}2、自定義Key生成器
除了通過SPEL表達式之外,還可以通過自定義key生成器的方式,Spring緩存模塊提供了org.springframework.cache.interceptor.KeyGenerator接口用于緩存key的生成聲明,因此我們可以自定義一個MyKeyGenerator類并實現了KeyGenerator接口 ,使用如下:
import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.lang.reflect.Method; import java.util.Arrays;@Configuration public class MyCacheConfig {@Beanpublic KeyGenerator myKeyGenerator(){return new KeyGenerator(){public Object generate(Object target, Method method, Object... params) {return method.getName()+"["+ Arrays.asList(params).toString()+"]";}};} }該方法測試用,關于緩存key的生成方式,網上有很多種策略。
使用時只需要修改注解的key屬性即可:
@Cacheable(cacheNames = "product",keyGenerator = "myKeyGenerator")3、 @CachePut
@CachePut注解的作用簡單的說一句話:既調用方法,又緩存數據。
/** @Author crush* @CachePut 即調用方法 有更新緩存數據* 運行時機:* 1 先調用目標方法* 2 將目標方法的結果緩存起來* 測試:* 1 先去查詢* 2 然后再更新* 3 然后再執行查詢 發現還是更新之前的數據* 4 發現他們緩存的時候 使用的key 是不一樣的 這個時候要使用相同的key***/ @CachePut(/*value = "userInfo", */key = "#userInfo.user_id") public UserInfo updateUser(UserInfo userInfo) {System.out.println("更新用戶信息");userInfoMapper.updateUser(userInfo);return userInfo; }4、@CacheEvict注解
該注解的作用根據指定的key或者是allEntries屬性值移除緩存中特性的鍵值對。
/* * @Author crush * @CacheEvict 緩存清除 * 可以通過key 來指定 要清除的值. * allEntries =true 指定清除這個緩存中的所有數據 * beforeInvocation =false * 默認代表緩存清除操作是在方法執行之后清除 如果出現異常 緩存就不會清除 * * beforeInvocation =true * 緩存的清除是否在方法之前執行 無論方法是否出現異常 緩存都清除 **/案例:
@CacheEvict(/*value = "userInfo",*/ key = "#user_id") public void delete(Integer user_id) {System.out.println("刪除了" + user_id + "用戶"); }5、@Caching注解
該注解是一個分組注解,作用是可以同時應用多個其他注解,該注解提供了3個屬性cacheable,put,evict分別用于組合@Cacheable、@CachePut、@CacheEvict三個注解
/* * @Author crush * 這個就是一個組合的 **/ @Caching(cacheable = {@Cacheable(/*value = "userInfo",*/key = "#user_name")},put = {@CachePut(/*value = "userInfo",*/key = "#result.user_id"),@CachePut(/*value = "userInfo",*/key = "#result.user_password")} ) public UserInfo selectByUserName(String user_name) {return userInfoMapper.selectByUserName(user_name); }springboot-cache 使用
步驟:
1、環境搭建:
DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` (`user_id` varchar(12) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '編號',`user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用戶名',`user_password` varchar(12) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密碼',PRIMARY KEY (`user_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;INSERT INTO `t_user` VALUES ('1', 'crush', '456789'); INSERT INTO `t_user` VALUES ('2', 'hehe', '456789');2、導入pom依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId> </dependency>3、項目結構
4、pojo層UserInfo類
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors;import java.io.Serializable;/*** @version 1.0* @author: crush* @date: 2021-04-10 16:21*/ @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) // lombok 注解 寫習慣了 寫了這個注解可以鏈式寫 // UserInfo userInfo = new UserInfo(); // userInfo.setUser_id("123").setUser_name("crush").setUser_password("abcdefg"); public class UserInfo implements Serializable {private String user_id;private String user_name;private String user_password; }5、yaml配置文件:
server:port: 8787 spring:datasource:type: com.alibaba.druid.pool.DruidDataSource #ali的數據源driver-class-name: com.mysql.cj.jdbc.Driverdruid:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/studentdb?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT mybatis:type-aliases-package: com.crush.pojomapper-locations: classpath:mapper/*.xml # configuration: # use-actual-param-name: true 駝峰命名6、mapper層:
@Mapper public interface UserInfoMapper {@Select("select * from t_user where user_id=#{user_id}")UserInfo selectByUserId(String user_id);@Update("UPDATE t_user SET user_name=#{user_name},user_password=#{user_password} WHERE user_id=#{user_id}")int updateUser(UserInfo userInfo);@Select("select * from t_user where user_name=#{user_name}")UserInfo selectByUserName(String user_name); }7、service和serviceImpl
package com.crush.service;import com.crush.mapper.UserInfoMapper; import com.crush.pojo.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.*; import org.springframework.stereotype.Service;/*** @version 1.0* @author: crush* @date: 2021-04-10 16:52*/ @CacheConfig(cacheNames = "userInfo") /* 在類上 可以定義一個公共的配置*/ @Service public class UserInfoService {@AutowiredUserInfoMapper userInfoMapper;/** @Author crush* 原理:* 1 自動配置類 :CacheAutoConfiguration* 2 緩存配置類* 3 哪個配置類生效* 4 給容器內注冊了一個CacheManager:ConcurrentMapCacheManager* 5 可以獲取何創建ConcurrentMapCacheManager 類型的緩存組件 他的作用就是講數據保存在ConcureentMapzhp* 運行流程:* @Cacheable* 1 方法執行之前 先去查詢Cache (緩存組件) 按照cacheNames 指定的名字獲取* 先去獲取相應的緩存 第一次獲取緩存如果沒有 Cache組件會自動創建* 2 去Cache 中查找緩存的內容 使用一個key 默認就是方法的參數* 3 沒有查到就返回結果* 4 將目標方法返回的結果 放進緩存中** @Cacheable 標注的方法 執行之前 先來檢查緩存中有沒有這個數據 默認按照參數的值作為key去查詢緩存* 如果沒有就運行方法并將結果放入緩存** 屬性:* cacheNames :指定緩存組的名字* key:緩存數據用的key 默認的key是根據參數值生成,如果存在 直接返回緩存中的值,否則執行該方法,并將返回值保存到緩存中* keyGenerator : 也可以用這個自定義key的值** condition: 指定符合條件下菜緩存 condition="#id>0"* // #a0> 1 表示第一個參數大與1* unless:否定緩存* unless="#a0==2" 如果第一個參數是2 就不緩存* sync:是否使用異步模式**/@Cacheable(/*cacheNames = "userInfo",*/key = "#user_id"/*,condition = "#id=1"*/) // #a0> 1 表示第一個參數大與1public UserInfo selectByUserId(String user_id) {System.out.println("根據id查詢用戶");return userInfoMapper.selectByUserId(user_id);}/** @Author crush* @CachePut 即調用方法 有更新緩存數據* 運行時機:* 1 先調用目標方法* 2 將目標方法的結果緩存起來* 測試:* 1 先去查詢* 2 然后再更新* 3 然后再執行查詢 發現還是更新之前的數據* 4 發現他們緩存的時候 使用的key 是不一樣的 這個時候要使用相同的key***/@CachePut(/*value = "userInfo", */key = "#userInfo.user_id")public UserInfo updateUser(UserInfo userInfo) {System.out.println("更新用戶信息");userInfoMapper.updateUser(userInfo);return userInfo;}/** @Author crush* @CacheEvict 緩存清除* 可以通過key 來指定 要清除的值.* allEntries =true 指定清除這個緩存中的所有數據* beforeInvocation =false* 默認代表緩存清除操作是在方法執行之后清除 如果出現異常 緩存就不會清除* 這句話的意思是 如果這個方法執行時出現異常 緩存就不會清除** beforeInvocation =true* 緩存的清除是否在方法之前執行 無論方法是否出現異常 緩存都清除**/@CacheEvict(/*value = "userInfo",*/ key = "#user_id")public void delete(Integer user_id) {System.out.println("刪除了" + user_id + "用戶");}/** @Author crush* 這個就是一個組合的**/@Caching(cacheable = {@Cacheable(/*value = "userInfo",*/key = "#user_name")},put = {@CachePut(/*value = "userInfo",*/key = "#result.user_id"),@CachePut(/*value = "userInfo",*/key = "#result.user_password")})public UserInfo selectByUserName(String user_name) {return userInfoMapper.selectByUserName(user_name);} }8、Controller層
import com.crush.pojo.UserInfo; import com.crush.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController;/*** @version 1.0* @author: crush* @date: 2021-04-10 16:20*/ @RestController public class HelloRedisController {@AutowiredUserInfoService userInfoService;@GetMapping("users/{user_id}")public UserInfo user(@PathVariable("user_id") String user_id) {return userInfoService.selectByUserId(user_id);}@GetMapping("users")public UserInfo update(UserInfo userInfo) {UserInfo userInfo1 = userInfoService.updateUser(userInfo);return userInfo1;}@GetMapping("dteUsers/{user_id}")public String delete(@PathVariable("user_id") Integer user_id) {userInfoService.delete(user_id);return "刪除成功";}@GetMapping("usersName/{user_name}")public UserInfo selectByName(@PathVariable("user_name") String user_name) {return userInfoService.selectByUserName(user_name);}}9、主啟動類:
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication @EnableCaching @MapperScan("com.crush.mapper") public class SpringbootRedisApplication {public static void main(String[] args) {SpringApplication.run(SpringbootRedisApplication.class, args);} }測試:
@Cacheable 測試
第一次測試查詢:
第二次執行查詢方法
@CachePut 測試
執行更新用戶方法
執行完更新用戶方法之后 再次執行 查詢方法 看控制臺會不會有輸出
@CachePut 測試
進行第二次測試 再次執行查詢方法 發現控制臺沒有輸出
總結
以上是生活随笔為你收集整理的springboot-cache的简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 查找--数据结构
- 下一篇: Optional 详解 Java