您的位置:首页 > 健康 > 美食 > 武汉网页建站_广州凡科互联网科技股份有限公司_线下引流推广方法_网站快速刷排名工具

武汉网页建站_广州凡科互联网科技股份有限公司_线下引流推广方法_网站快速刷排名工具

2024/12/23 12:13:38 来源:https://blog.csdn.net/weixin_45541665/article/details/144502630  浏览:    关键词:武汉网页建站_广州凡科互联网科技股份有限公司_线下引流推广方法_网站快速刷排名工具
武汉网页建站_广州凡科互联网科技股份有限公司_线下引流推广方法_网站快速刷排名工具

概述

在商业中 “现金为王”,而在互联网整个软件世界中,有一个与之相近的说法是“缓存为王”。

本文我们重点说明缓存方向:将方法的返回值缓存起来,下次再调用该方法时,如果方法的参数与之前调用时的参数相同,则会直接返回缓存中的结果,而不会再执行方法体。这样可以提高方法的执行效率

优点

  • 提高性能:缓存可以将方法的结果存储在内存中,后续对相同参数的方法调用可以直接从缓存中获取结果,避免重复计算,提高方法的执行效率。
  • 减轻数据库压力:对于需要频繁访问数据库的方法,可以将结果缓存在内存中,减轻数据库的压力,提高数据库的响应速度。
  • 简化代码逻辑:通过使用缓存,可以避免编写复杂的手动缓存代码或条件判断逻辑,使代码更简洁、可读性更好。

缺点

  • 内存占用:缓存的数据存储在内存中,因此如果缓存的数据量过大,会消耗大量的内存资源。在使用缓存时需要合理安排系统的内存和缓存容量。
  • 数据一致性:使用缓存后,需要注意维护数据的一致性。当数据发生变化时,需要及时更新缓存,以避免脏数据的问题。可通过合理设计缓存策略和使用缓存失效机制来解决这个问题。
  • 缓存失效:缓存的有效期限需要合理设置。如果缓存的有效期太长,可能导致数据更新不及时;如果缓存的有效期太短,可能增加重复执行代码的次数。需要根据具体业务场景来选择合适的缓存有效期。
  • 缓存击穿:当某个缓存条目在缓存失效时,同时有大量的并发请求到达时,可能会导致缓存击穿问题,即大量请求直接击穿到数据库。可以通过加锁或使用分布式锁等机制来避免缓存击穿。

注解介绍

Spring缓存机制通过 @EnableCaching开启,配合 @Cacheable、 @CachePut、 @CacheEvict等注解,为Java应用提供了一种声明式管理缓存的方式。这些注解使得缓存配置变得简洁明了,允许开发者轻松实现数据的自动缓存、更新和清除,从而优化应用性能,减少不必要的计算和数据访问开销。

1. 启用缓存支持

@EnableCaching 注解用于在Spring配置类上启用缓存管理功能。

  • 注解属性介绍

无属性。

  • 注解业务案例
1.  @Configuration2.  @EnableCaching3.  public class CacheConfig {4.      // 配置其他Bean`5.  }

2. 缓存结果

@Cacheable 注解用于声明一个方法的结果是可缓存的。

  • 注解属性介绍

  • valuecacheNames: 指定缓存名称,可以是单个或多个。

  • key: 指定缓存键的SpEL表达式。

  • condition: 指定缓存的条件SpEL表达式。

  • unless: 指定不缓存的条件SpEL表达式。

  • 注解业务案例 单一缓存名称和键:

1.  @Cacheable("books")2.  public Book findBookById(String id) {3.      // 业务逻辑4.  }

多个缓存名称和条件:

1.  @Cacheable(value = {"books", "archivedBooks"}, condition = "#id.length() > 10")
2.  public Book findBookWithComplexKey(String id) {
3.      // 业务逻辑
4.  }6.  @Service
7.  public class MyService {9.      /**10.       `* 一个使用 @Cacheable 所有属性的案例。`11.       `*` 12.       `* @param id 用户ID`13.       `* @return 返回用户对象`14.       `*/15.      @Cacheable(16.          value = "users",          // 缓存名称`17.          key = "#id",              // 缓存键,使用SpEL表达式`18.          condition = "#id.length() > 3",  // 缓存条件,只有当ID长度大于3时才缓存`19.          unless = "#result == null" // 除非条件,如果结果为null,则不缓存`20.      )
21.      public User findUserById(String id) {22.          // 模拟数据库查询操作,这里假设ID长度小于3时没有结果`23.          if (id == null || id.length() <= 3) {24.              return null;25.          }26.          return performDatabaseQuery(id);27.      }29.      private User performDatabaseQuery(String id) {30.          // 模拟数据库查询逻辑`31.          return new User(id, "Name based on ID");32.      }33.  }

3. 更新缓存

@CachePut 注解用于在方法执行后更新缓存。

  • 注解属性介绍

@Cacheable相同。

  • 注解业务案例
 1.  @CachePut("books")2.  public Book updateBookDetails(String id, Book details) {3.  // 业务逻辑4.  }5.  6.  @Service7.  public class MyService {8.  9.  /**10. * 使用 @CachePut 所有属性的案例。11. *12. * @param user 用户对象,包含ID13. * @return 更新后的用户对象14. */15. @CachePut(16. 	value = "users", // 缓存名称17. 	key = "#user.id", // 缓存键,使用SpEL表达式18. 	condition = "#user.age > 18" // 条件,只有当用户年龄大于18时才更新缓存19. )20. public User updateUserProfile(User user) {21. // 模拟更新用户信息的业务逻辑22. return performUpdate(user);23. }24. 25. private User performUpdate(User user) {26. // 模拟更新逻辑27. user.setName("Updated Name");28. return user;29. }30. }

4. 清除缓存

@CacheEvict 注解用于在方法执行后清除缓存。

注解属性介绍

  • valuecacheNames: 指定缓存名称,可以是单个或多个。

  • allEntries: 清除所有缓存项。

  • condition: 指定清除缓存的条件SpEL表达式。

注解业务案例

清除特定缓存名称的条目:

1.  @CacheEvict("books")2.  public void deleteBook(String id) {3.      // 业务逻辑4.  }

清除所有缓存名称的所有条目:

1.  @CacheEvict(allEntries = true)2.  public void clearAllCaches() {3.      // 业务逻辑4.  }

5. 组合缓存操作

@Caching 注解用于组合多个缓存操作。

  • 注解属性介绍

value: 包含多个缓存操作的数组。

  • 注解业务案例

1.  @Caching(2.      cacheable = {@Cacheable("books")},3.      put = {@CachePut("books")},4.      evict = {@CacheEvict("archivedBooks")}5.  )6.  public Book processBook(String id, Book details) {7.      // 业务逻辑8.  }

代码演示

redis依赖安装

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.21</version></dependency>
  • redis配置文件
spring:redis:# 连接地址host: "127.0.0.1"# 端口port: 6379# 数据库database: 1password: helloworld# 连接超时connect-timeout: 5s# 读超时timeout: 5s# Lettuce 客户端的配置lettuce:# 连接池配置pool:# 最小空闲连接min-idle: 0# 最大空闲连接max-idle: 8# 最大活跃连接max-active: 8# 从连接池获取连接 最大超时时间,小于等于0则表示不会超时max-wait: -1ms

接口缓存配置类

框架给我们提供了 @Cacheable 注解用于缓存方法返回内容。但是 @Cacheable 注解 不能 定义缓存 有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。

框架给我们提供的 RedisCacheManager 类,是 准对这一块的 就配置类, 我们可以根据此类,自己实现 缓存有效期 的功能。

package com.xuzhongkj.configrations;import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.validation.constraints.NotNull;
import java.time.Duration;
import java.util.Objects;@Configuration
@EnableCaching
public class CustomRedisCacheManager {private String keyPreFix = "whero";private RedisSerializer<String> keySerializer() {return new StringRedisSerializer();}private RedisSerializer<Object> valueSerializer() {// fastjson 中的类return new GenericFastJsonRedisSerializer();}/** @description 配置自定义 缓存管理器: RedisCacheManager**/@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {// 缓存注解 配置:RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()//设置 key 为String.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//设置 value 为自动转Json的Object.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))// 使用 prefixCacheNameWith 需要注意系统自动拼接的双”:“问题.computePrefixWith(cacheName -> keyPreFix + ":" + cacheName + ":");RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisTemplate.getConnectionFactory()));RedisCacheManager redisCacheManager = new CustomRedisCacheManagerToolsClass(redisCacheWriter, config);return redisCacheManager;}
}/*** @Title: 自定义redis缓存管理器, 为了实现 缓存有效期的 动态性*/
class CustomRedisCacheManagerToolsClass extends RedisCacheManager {public static final String SEPARATOR = "#";public CustomRedisCacheManagerToolsClass(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {super(cacheWriter, defaultCacheConfiguration);}@Overrideprotected RedisCache createRedisCache(@NotNull(message = "缓存名称不能为空") String name, RedisCacheConfiguration cacheConfiguration) {// 举例说明: name = "bookCourse:getCourseId#7D"if (name.contains(SEPARATOR)) {String[] spelStr = name.split(SEPARATOR);String key = spelStr[0];String valueStr = spelStr[1];int length = valueStr.length();if (length >= 2) {String cycleTimeStr = valueStr.substring(0, length - 1);if (cycleTimeStr.matches("\\d+")) {long cycleTime = Long.parseLong(cycleTimeStr);String cycleUnit = valueStr.substring(length - 1, length);if (cycleUnit.equals("D")) {//表示天return super.createRedisCache(key, cacheConfiguration.entryTtl(Duration.ofDays(cycleTime)));}if (cycleUnit.equals("H")) {//表示小时return super.createRedisCache(key, cacheConfiguration.entryTtl(Duration.ofHours(cycleTime)));}if (cycleUnit.equals("M")) {//表示分钟return super.createRedisCache(key, cacheConfiguration.entryTtl(Duration.ofMinutes(cycleTime)));}if (cycleUnit.equals("S")) {//表示秒return super.createRedisCache(key, cacheConfiguration.entryTtl(Duration.ofSeconds(cycleTime)));} else {// 都不是则使用默认配置return super.createRedisCache(name, cacheConfiguration);}}}}return super.createRedisCache(name, cacheConfiguration);}
}

这里面简单对 RedisCacheConfiguration 缓存配置做一下说明:

  • serializeKeysWith():设置 Redis 的 key 的序列化规则。
  • erializeValuesWith():设置 Redis 的 value 的序列化规则。
  • computePrefixWith():计算 Redis 的 key 前缀。
  • cacheConfiguration.entryTtl(): 设置 @Cacheable 注解缓存的有效期。

测试使用

service层

package com.xuzhongkj.services.impls;import com.xuzhongkj.pojo.Userswtt;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;@Service
public class WttService {@Cacheable(cacheNames = {"bookCourse:getCourseId#7M"}, key = "#name")public Userswtt getName (String name) {System.out.println("-------  创建 -----------"+name);Userswtt u = new Userswtt();u.setOpenid("qwejlksdfjkdf");u.setAge(11);u.setAvatar("https:/asdfj;askdf");u.setUid(123L);return  u;}@CachePut(cacheNames = {"bookCourse:getCourseId#7M"}, key = "#name")public Userswtt EdtName (String name) {System.out.println("---------- 更新 --------"+name);Userswtt u = new Userswtt();u.setOpenid("qwejlksdfjkdf");u.setAge(22);u.setAvatar("https:/asdfj;askdf");u.setUid(123L);return  u;}@CacheEvict(cacheNames = {"bookCourse:getCourseId#7M"}, key = "#name")public Userswtt DelName (String name) {System.out.println("--------- 删除 ---------"+name);Userswtt u = new Userswtt();return  u;}
}

controller 层

@RestController
@Slf4j
@RequestMapping("/test")
public class WttTest {@Autowiredprivate WttService wttService;@GetMapping("/wtt")public Userswtt a1() {Userswtt name = wttService.getName("testResObj");return name;}@GetMapping("/wtt2")public Userswtt a2() {Userswtt name = wttService.EdtName("testResObj");return name;}@GetMapping("/wtt3")public Userswtt a3() {return wttService.DelName("testResObj");}

redis中键值对的存储情况:

  • key:

whero:bookCourse:getCourseId:testResObj

  • value

{“@type”:“com.xuzhongkj.pojo.Userswtt”,“age”:11,“avatar”:“https:/asdfj;askdf”,“openid”:“qwejlksdfjkdf”,“uid”:123}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com