当前位置: 首页 > wzjs >正文

企业网站建设官网郑州网络推广

企业网站建设官网,郑州网络推广,工作纪律生活纪律研讨发言,深圳市外贸网站一、前言 在高性能服务架构设计里,缓存是关键环节。常规做法是将热点数据存于 Redis/MemCache 等远程缓存,缓存未命中时再查数据库,以此提升访问速度、降低数据库压力 。 随着发展,架构有了改进,部分场景下单纯远程缓…

一、前言

在高性能服务架构设计里,缓存是关键环节。常规做法是将热点数据存于 Redis/MemCache 等远程缓存,缓存未命中时再查数据库,以此提升访问速度、降低数据库压力 。

随着发展,架构有了改进,部分场景下单纯远程缓存不够,需结合本地缓存(如 Guava cache、Caffeine ),形成本地缓存(一级缓存) + 远程缓存(二级缓存)的两级缓存架构,进一步提升程序响应与服务性能,其基础访问流程如下(暂不考虑并发等复杂问题):

[此处插入原流程图片,替换路径为合理展示形式,如保留./assets/2.jpeg,若为线上展示需处理为可访问链接]

二、优点与待解决问题

(一)优势

相比单纯远程缓存,两级缓存有以下优势:

  • 访问速度快:本地缓存基于内存,对变更 / 实时性要求低的数据,存入本地可大幅提升访问速度。
  • 减少网络开销:降低与远程缓存的数据交互,减少网络 I/O 耗时,节省网络通信成本。

(二)需解决问题

设计时要考虑诸多问题,核心是数据一致性

  • 两级缓存与数据库需同步,数据修改时,本地、远程缓存应同步更新。
  • 分布式环境下,一级缓存节点间存在一致性问题。一个节点修改本地缓存后,需通知其他节点刷新,否则会读过期数据,可借 Redis 发布 / 订阅功能解决。

此外,缓存过期时间、策略及多线程访问等问题也需关注,本文先聚焦两级缓存的代码实现。

三、准备工作

(一)技术选型

整合Caffeine(最强本地缓存) 为一级缓存、Redis(性能优) 为二级缓存,搭建 SpringBoot 项目,引入依赖:

<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.9.2</version>
</dependency>
<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>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.1</version>
</dependency>

(二)Redis 配置

配置RedisTemplate ,处理连接工厂、序列化等:

/*** Redis缓存配置类* @author ZhuZiKai* @date 2022/3/31 0014*/
@Configuration
@EnableCaching
@EnableAspectJAutoProxy 
public class RedisConfig extends CachingConfigurerSupport {@Beanpublic FastJsonRedisSerializer fastJson2JsonRedisSerializer() {return new FastJsonRedisSerializer(Object.class);}@Beanpublic StringRedisSerializer StringRedisSerializer() {return new StringRedisSerializer();}@Bean("redis")@Primarypublic RedisTemplate initRedisTemplate(RedisConnectionFactory redisConnectionFactory,StringRedisSerializer stringRedisSerializer,FastJsonRedisSerializer fastJson2JsonRedisSerializer) throws Exception {RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setValueSerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);redisTemplate.setDefaultSerializer(stringRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

四、代码实战:两级缓存管理实现

(一)V1.0 版本:Spring 缓存注解方案

Spring 提供CacheManager 接口与注解(@Cacheable/@CachePut/@CacheEvict ),简化缓存操作。

1. 注解说明
  • @Cacheable:按 key 查缓存,命中则直接返回;未命中则执行方法,结果入缓存。
  • @CachePut:无论缓存是否存在,执行方法并强制更新缓存。
  • @CacheEvict:执行方法后,移除对应缓存数据。
2. 配置CacheManager
@Configuration
public class CacheManagerConfig {@Beanpublic CacheManager cacheManager(){CaffeineCacheManager cacheManager=new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().initialCapacity(128).maximumSize(1024).expireAfterWrite(60, TimeUnit.SECONDS));return cacheManager;}
}

启动类添加@EnableCaching ,开启缓存支持。

3. Service 层改造
  • 查询方法:用@Cacheable ,保留业务与 Redis 操作逻辑,Caffeine 缓存交 Spring 管理:
@Cacheable(value = "order",key = "#id")
public Order getOrderById(Long id) {String key= CacheConstant.ORDER + id;// 查RedisObject obj = redisTemplate.opsForValue().get(key);if (Objects.nonNull(obj)){log.info("get data from redis");return (Order) obj;}// Redis无则查DBlog.info("get data from database");Order myOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getId, id));// 结果入RedisredisTemplate.opsForValue().set(key,myOrder,120, TimeUnit.SECONDS);return myOrder;
}

  • 更新方法:用@CachePut ,移除手动更新 Caffeine 操作(由 Spring 管理):
@CachePut(cacheNames = "order",key = "#order.id")
public Order updateOrder(Order order) {log.info("update order data");orderMapper.updateById(order);// 更新RedisredisTemplate.opsForValue().set(CacheConstant.ORDER + order.getId(),order, 120, TimeUnit.SECONDS);return order;
}

注意:方法需定义返回值,否则可能缓存空对象,影响后续查询。

  • 删除方法:用@CacheEvict ,仅处理 Redis 缓存删除:
@CacheEvict(cacheNames = "order",key = "#id")
public void deleteOrder(Long id) {log.info("delete order");orderMapper.deleteById(id);redisTemplate.delete(CacheConstant.ORDER + id);
}

此方案将本地缓存交 Spring 管理,Redis 缓存手动操作,降低业务入侵性。

(二)V2.0 版本:自定义注解 + 切面方案

进一步解耦,通过自定义注解与切面,实现对业务无入侵的缓存管理。

1. 自定义注解

定义@DoubleCache ,支持缓存存取、删除,适配 SpringEL 表达式:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DoubleCache {String cacheName();String key(); // 支持SpringELlong l2TimeOut() default 120;CacheType type() default CacheType.FULL;
}// 缓存操作类型枚举
public enum CacheType {FULL,   // 存取PUT,    // 只存DELETE  // 删除
}
2. SpringEL 表达式解析

解析注解中key 的表达式,适配方法参数:

public static String parse(String elString, TreeMap<String,Object> map){elString=String.format("#{%s}",elString);ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();map.entrySet().forEach(entry->context.setVariable(entry.getKey(),entry.getValue()));Expression expression = parser.parseExpression(elString, new TemplateParserContext());return expression.getValue(context, String.class);
}
3. 配置 Caffeine 缓存
@Configuration
public class CaffeineConfig {@Beanpublic Cache<String,Object> caffeineCache(){return Caffeine.newBuilder().initialCapacity(128)// 初始容量.maximumSize(1024)// 最大容量.expireAfterWrite(60, TimeUnit.SECONDS)// 过期时间.build();}
}
4. 切面实现缓存逻辑

通过切面拦截@DoubleCache 注解,统一处理缓存读写、删除:

@Slf4j 
@Component 
@Aspect 
@AllArgsConstructor
public class CacheAspect {private final Cache<String,Object> cache;private final RedisTemplate redisTemplate;@Pointcut("@annotation(com.cn.dc.annotation.DoubleCache)")public void cacheAspect() {}@Around("cacheAspect()")public Object doAround(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();// 解析方法参数,封装SpringEL上下文String[] paramNames = signature.getParameterNames();Object[] args = point.getArgs();TreeMap<String, Object> treeMap = new TreeMap<>();for (int i = 0; i < paramNames.length; i++) {treeMap.put(paramNames[i],args[i]);}DoubleCache annotation = method.getAnnotation(DoubleCache.class);String elResult = ElParser.parse(annotation.key(), treeMap);String realKey = annotation.cacheName() + CacheConstant.COLON + elResult;// 按操作类型处理if (annotation.type()== CacheType.PUT){Object object = point.proceed();redisTemplate.opsForValue().set(realKey, object,annotation.l2TimeOut(), TimeUnit.SECONDS);cache.put(realKey, object);return object;} else if (annotation.type()== CacheType.DELETE){redisTemplate.delete(realKey);cache.invalidate(realKey);return point.proceed();}// 读写流程:先查CaffeineObject caffeineCache = cache.getIfPresent(realKey);if (Objects.nonNull(caffeineCache)) {log.info("get data from caffeine");return caffeineCache;}// 再查RedisObject redisCache = redisTemplate.opsForValue().get(realKey);if (Objects.nonNull(redisCache)) {log.info("get data from redis");cache.put(realKey, redisCache);return redisCache;}// 都无则查数据库,结果入缓存log.info("get data from database");Object object = point.proceed();if (Objects.nonNull(object)){redisTemplate.opsForValue().set(realKey, object,annotation.l2TimeOut(), TimeUnit.SECONDS);cache.put(realKey, object);        }return object;}
}
5. Service 层简化

只需添加自定义注解,专注业务逻辑:

@DoubleCache(cacheName = "order", key = "#id",type = CacheType.FULL)
public Order getOrderById(Long id) {return orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getId, id));
}@DoubleCache(cacheName = "order",key = "#order.id",type = CacheType.PUT)
public Order updateOrder(Order order) {orderMapper.updateById(order);return order;
}@DoubleCache(cacheName = "order",key = "#id",type = CacheType.DELETE)
public void deleteOrder(Long id) {orderMapper.deleteById(id);
}

五、总结与思考

本文按业务入侵程度,介绍两种两级缓存实现:

  • V1.0:借 Spring 缓存注解,半入侵式管理,本地缓存交 Spring,Redis 手动操作。
  • V2.0:自定义注解 + 切面,完全解耦缓存逻辑,业务代码更简洁。

实际项目中,是否用两级缓存需结合业务。若 Redis 满足需求,无需强制引入,因实际使用涉及并发、事务回滚、缓存策略适配等复杂问题。需权衡数据特性(如哪些适合一级 / 二级缓存)、一致性保障成本,再决定架构方案,让缓存真正成为服务性能的 “助推器” 而非 “负担” 。

http://www.dtcms.com/wzjs/376271.html

相关文章:

  • 返利网站程序好项目推荐平台
  • wordpress 留言簿搜索引擎优化网站
  • 影楼网站建设网站建设7个基本流程
  • 网站长尾词挖掘企业网站推广方案
  • 做卖号网站吗慧达seo免登录发布
  • 南宁seo网站推广服务win10优化大师好用吗
  • 跟有流量的网站做友情链接搜狗搜索引擎优化指南
  • 徐州网站建设要多少钱深圳全网营销系统
  • 黄页网页的推广网站推广普通话奋进新征程演讲稿
  • 做网站如何选域名网络媒体广告代理
  • 化妆品网页设计论文合肥seo报价
  • 网页设计代码为什么没有颜色广州seo网站开发
  • 做私服网站电话厦门网络推广
  • 别人做的网站自己根目录吗福州百度关键词优化
  • 网站搭建好了跳转到其他网seo外包靠谱
  • wordpress编辑区块报警谷歌seo网站优化
  • 邯郸做网站公司哪家好百度收录最新方法
  • 网站背景如何做直通车怎么开才有效果
  • 模版营销型网站怎么做优化人员配置
  • 家具行业网站建设关键词优化资讯
  • 西安东郊做网站百度首页广告
  • 燕郊建设局网站网络推广策划方案怎么写
  • 门户网站建设的报价成人技能培训班有哪些
  • 网站报名怎么做核心关键词举例
  • 网页制作与网站建设完全学习手册楚雄百度推广电话
  • 苏州美丽乡村建设网站百度指数是什么意思
  • 无锡市建设局一号通网站免费二级域名生成网站
  • 自己的网站做防伪码百度推广方式
  • 网页访问wordpress网站关键词优化的步骤和过程
  • 网站建设培训班软文投稿平台有哪些