redis缓存和本地缓存的应用设计

数据查询顺序

一级缓存:本地缓存 -》二级缓存:redis缓存 -》数据库

在这里插入图片描述

本地缓存和分布式缓存

  • 本地缓存基于jvm, 意思是程序放在哪,数据就存储在哪,不需要网络请求,特别快,但是需要占用jvm的内存,所以存储的东西不能太大,也不能太久,有内存淘汰机制。缓存组件包括: Guava CacheCaffeineEncache
  • 分布式缓存:请求需要网络传输,速度慢一点,组件包括:RedisMongoDB

哪些场景用到缓存?

  • 邀请入会的助力排行榜,key= 活动id+pageSize,缓存过期时间1分钟
/*** 查询邀请入会的助力排行榜* @param activityId* @param pageSize* @return*/@Override@MallCache(value = "queryHelpRankingList", expireTime = 1, timeUnit = TimeUnitEnum.MINUTES)public List<ActivityHelpStatisticsEntity> queryRankingList(String activityId, Integer pageSize) {List<ActivityHelpStatisticsLogPO> statisticsLogs = mapper.queryRankingList(activityId, pageSize);if (CollectionUtils.isEmpty(statisticsLogs)) {return new ArrayList<>();}return statisticsLogs.stream().map(po -> ActivityHelpStatisticsConverter.convert(po)).collect(Collectors.toList());}
  • 验证用户是否在分组中,可以=groupId, String nascentId, String groupIds,缓存五秒
 @MallCache(value = "checkExistGroup", expireTime = 5, timeUnit = TimeUnitEnum.SECONDS)private boolean checkExistGroupCache(long groupId, String nascentId, String groupIds){return OpenPlatformHelperV4.checkExistGroup(groupId, nascentId, groupIds);}
  • 等级体系,缓存30分钟
@MallCache(value = "GradeSystem", expireTime = 30)@Overridepublic GradeSystem queryGradeSystem(Long groupId, Long viewId, Long shopId) {GradeSystemGetRequest gradeSystemGetRequest = new GradeSystemGetRequest();gradeSystemGetRequest.setViewId(viewId);gradeSystemGetRequest.setShopId(shopId);gradeSystemGetRequest.setGroupId(groupId);GradeSystemGetResponse gradeResponse = OpenPlatformClient.exec(groupId, gradeSystemGetRequest);GradeSystem result = gradeResponse.getResult();return result;}
  • 等级名称 30分钟,这种需要调用三方接口,缓存可以减少调用接口次数
/*** 获取等级名称** @param groupId* @param shopId* @param grade* @return*/@MallCache(value = "CustomerGradeName", expireTime = 30)public String getCustomerGradeName(long groupId, long shopId, int grade) {List<Long> viewIds = cloudPlatformService.queryViewIdByAreaIdOrBrandId(groupId, getMallId(), Arrays.asList(shopId));return getCustomerGradeName(groupId, shopId, grade, viewIds.get(0));}public String getCustomerGradeName(long groupId, long shopId, int grade, long viewId) {if (grade == 0) {return "非会员";}GradeInfoGetResponse response = OpenPlatformHelperV4.getGradeInfo(groupId, shopId, grade, viewId);AssertUtil.assertTrue(response != null && response.getSuccess(), "获取等级信息失败");GradeInfo gradeInfo = response.getResult();AssertUtil.assertNotNull(gradeInfo, "获取等级信息失败");return gradeInfo.getGradeName();}
@Override@MallCache(value = "VIEWID", expireTime = 60)public Long queryViewIdByAreaIdOrBrandId(Long groupId, Long mallId, Long shopId) {WmCompanyDO company = WmCompanyDao.dao().findByCompanyId(groupId);List<Long> viewIds = CloudPlatformHelper.queryViewIdByShopIds(Arrays.asList(shopId), groupId, company.getViewOperationType());AssertUtil.assertTrue(!CollectionUtils.isEmpty(viewIds), "查询运营视角失败,请检查");return viewIds.get(0);}
  • 线下门店列表 缓存60分钟,这种东西一般不会经常变化,且进入首页就要用,
/**** @Description  获取线下门店列表,并存入缓存* @Param* @param groupId* @param shopId* @return*/@MallCache(value = "offlineShops", expireTime = 60)public TableResponse<Record> getOfflineShops(Long groupId,Long shopId){TableResponse<Record> tableResponse = new TableResponse<>();List<Record> offlineShops = WmOfflineShopDao.dao().getOfflineByDigitalShopId(groupId,shopId);tableResponse.setData(offlineShops);return tableResponse;}
/*** 积分别名** @param groupId* @param shopId* @param sysId* @return*/@MallCache(value = "getGameIntegralAlias", expireTime = 60)public String getIntegralAlias(Long groupId, Long mallId, Long shopId, String sysId) {Long viewId = cloudViewUtil.getViewId(groupId, mallId, shopId);return openIntegralCacheUtil.getIntegralAliasCache(groupId, mallId, shopId, sysId, viewId);}

项目中如何做缓存设计?

基于AOP的切面注解

目录结构

在这里插入图片描述

自定义@MallCache注解

/*** 二级缓存:redis+本地缓存* 默认启用redis缓存,本地缓存由withLocalCache控制* @author*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MallCache {String value() default "MallCache::";/*** 是否启用本地缓存** @return*/boolean withLocalCache() default false;/*** 分钟级缓存:* 一级缓存的失效时间为10分钟,这里二级缓存的失效时间应该大于等于10分钟,* 不然失去二级缓存的意义* 秒级缓存:本地缓存失效时间是5s* @return 缓存失效时间 (默认分钟)*/long expireTime() default 20;/*** 缓存失效时间单位* TimeUnitEnum.MINUTES使用分钟级缓存* TimeUnitEnum.SECONDS使用秒级缓存** @return*/TimeUnitEnum timeUnit() default TimeUnitEnum.MINUTES;
}

引用注解@MallCache

	/*** 查询邀请入会的助力排行榜前100* @param activityId* @param pageSize* @return*/@Override@MallCache(value = "queryHelpRankingList", expireTime = 1, timeUnit = TimeUnitEnum.MINUTES)public List<ActivityHelpStatisticsEntity> queryRankingList(String activityId, Integer pageSize) {List<ActivityHelpStatisticsLogPO> statisticsLogs = mapper.queryRankingList(activityId, pageSize);if (CollectionUtils.isEmpty(statisticsLogs)) {return new ArrayList<>();}return statisticsLogs.stream().map(po -> ActivityHelpStatisticsConverter.convert(po)).collect(Collectors.toList());}

需要得到的效果

比如 上面的queryRankingList(String activityId, Integer pageSize) 方法引用了@MallCache(value = "queryHelpRankingList", expireTime = 1, timeUnit = TimeUnitEnum.MINUTES)注解。
最终执行过程应该是:

  1. 首先用 queryHelpRankingListactivityIdpageSize拼接成key,比如activityId=hh34hrnih352nb3kh5o3g34, pageSize=100,那拼接的key = queryHelpRankingList_hh34hrnih352nb3kh5o3g34_100
  2. 拿着key去本地查缓存,本地缓存有的话返回给前端
  3. 本地缓存没有就去查redis缓存,redis缓存有的话返回给前端,同时更新到本地缓存
  4. redis缓存没有的话,调用queryRankingList(String activityId, Integer pageSize)的代码去查数据库
  5. 同时将数据库的最新数据更新到redis和本地缓存

LocalCacheAspect

用于切面加强

@Slf4j
@Aspect
@Component
@Order(-1)
@ConditionalOnBean(CommonCacheManager.class)
public class LocalCacheAspect {@Autowiredprivate CommonCacheManager commonCacheManager;@Around("@annotation(com.nascent.ecrp.mall.core.cache.annotation.MallCache)")public Object mallCache(ProceedingJoinPoint proceedingJoinPoint){MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();Method method = methodSignature.getMethod();Type genericReturnType = methodSignature.getMethod().getAnnotatedReturnType().getType();MallCache mallCache = method.getAnnotation(MallCache.class);String cachePrefix = mallCache.value();long expire = mallCache.expireTime();boolean withLocalCache = mallCache.withLocalCache();TimeUnitEnum timeUnit = mallCache.timeUnit();Object[] args = proceedingJoinPoint.getArgs();// 用切点方法的参数拼接成cacheKey 比如groupId_viewId_shopIdString cacheKey = Arrays.stream(args).map(arg -> {return String.valueOf(arg);}).collect(Collectors.joining("_"));Object result = commonCacheManager.queryData(cachePrefix + "_" + cacheKey,expire ,timeUnit, withLocalCache, genericReturnType ,()->{try {// 接口查询数据库拿到数据return proceedingJoinPoint.proceed(args);} catch (Throwable throwable) {log.error("LocalCacheAspect.mallCache 异常:{}", throwable);return null;}});return result;}
}

CommonCacheFactory

本地缓存的初始化类

  • 初始化缓存,设置缓存的级别,最大缓存数,过期时间
  • 增加缓存,删除缓存
public class CommonCacheFactory {/*** 秒级时间的缓存*/private static Cache<String, Object> localCacheSecond;/*** 分钟时间的缓存*/private static Cache<String, Object> localCacheMinute;static {localCacheSecond = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(5, TimeUnit.SECONDS).recordStats().build();localCacheMinute = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES).recordStats().build();}private CommonCacheFactory(){}public static  Cache<String, ? > get() {return getMinute();}public static void set(String key, Object value){setMinute(key, value);}public static  Cache<String, ? > getSecond() {return localCacheSecond;}public static void setSecond(String key, Object value){localCacheSecond.put(key, value);}public static  Cache<String, ? > getMinute() {return localCacheMinute;}public static void setMinute(String key, Object value){localCacheMinute.put(key, value);}}

CommonCacheManager

本地缓存管理类,用于本地缓存的查询和更新

@Slf4j
@Component
public class CommonCacheManager extends AbstractCacheManager<String, String>{private static final String LOCAL_CACHE_ENABLE_KEY =  "LOCAL_CACHE_ENABLE";@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Overridepublic boolean useCache() {// todo 优化成直接在内存中获取String enable = redisTemplate.opsForValue().get(LOCAL_CACHE_ENABLE_KEY);if(StringUtil.isNotBlank(enable) && "CLOSE".equals(enable)){return false;}else {return true;}}@Overridepublic Cache<String, String> primaryCache(TimeUnitEnum timeUnit) {if(TimeUnitEnum.SECONDS.equals(timeUnit)){Cache<String, String> stringResultCache = (Cache<String, String>) CommonCacheFactory.getSecond();return stringResultCache;}return (Cache<String, String>) CommonCacheFactory.getMinute();}@Overridepublic String cacheKey() {return "LOCAL::CACHE::";}public <T> T queryData(String k, Long expireTime, TimeUnitEnum timeUnit, boolean withLocalCache, Type type, Supplier<T> supplier) {if (!useCache()) {// 不使用本地缓存,默认是使用的log.info("直接在缓存中获取数据:{}", k);return supplier.get();// supplier.get()能获取函数的返回值,直接返回数据库数据}try {CacheContext<String,T> resultCacheContext =CacheContext.<String,T>builder().key(cacheKey() + k).reference(type).expireSeconds(expireTime).timeUnit(timeUnit.getTimeUnit()).callback(() -> supplier.get())// 数据库数据,这里只作为实参,还并没有调用.build();// 不用本地缓存,用redis缓存if(!withLocalCache){return JSON.parseObject(getFromSecondary(resultCacheContext), type);}// 用本地缓存String result = primaryCache(timeUnit).get(k, (x) -> getFromSecondary(resultCacheContext));return JSON.parseObject(result, type);} catch (Exception e) {log.error("一级缓存获取数据失败:{}", e.getMessage());return supplier.get();}}}

AbstractCacheManager

redis缓存的管理接口类

@Slf4j
public abstract class AbstractCacheManager<K, V> implements CacheManage<K, V> {/** 查询redis缓存、存在则读取并返回,不存在则更新成最新数据** @param context* @return* @param <T>*/protected <T> V getFromSecondary(CacheContext<K,T> context) {K key = context.key;T dbValue = null;try {String valueFromSecondary = secondaryCache().getValueFromSecondary(key);// 二级缓存,即redis层缓存,有数据就使用redis缓存if (StringUtil.isNotBlank(valueFromSecondary)) {return (V) valueFromSecondary;}// redis缓存没有,查询数据库dbValue = context.getCallback().get();if (dbValue == null) {return null;}Object jsonValue = JSONObject.toJSONString(dbValue);//把数据库的数据跟新到二级缓存secondaryCache().setValueForSecondary(key, context.expireSeconds, context.timeUnit, jsonValue);return (V)jsonValue;} catch (Exception e) {log.error("二级缓存中获取数据失败:{}", e.getMessage());return null;}}@Overridepublic SecondaryCache secondaryCache() {RedisSecondaryCache redisSecondaryCache = SecondaryCacheFactory.create(RedisSecondaryCache.class);return redisSecondaryCache;}@Overridepublic void invalidate(Object o) {for(TimeUnitEnum timeUnit : TimeUnitEnum.values()){primaryCache(timeUnit).invalidate(o);}secondaryCache().invalidate(o);}@Overridepublic void invalidateAll(List o) {for(TimeUnitEnum timeUnit : TimeUnitEnum.values()){primaryCache(timeUnit).invalidateAll();}secondaryCache().invalidateAll(o);}@Overridepublic Map<String,Map<String, V>> showAsMap() {Map<String,Map<String, V>> map = Maps.newHashMap();for(TimeUnitEnum timeUnit : TimeUnitEnum.values()) {Map<String,V> newMap = Maps.newHashMap();primaryCache(timeUnit).asMap().entrySet().forEach(entry -> newMap.put(Objects.toString(entry.getKey()),entry.getValue()));map.put(timeUnit.name(), newMap);}return map;}@Overridepublic Map<String,Set<K>> keys() {Map<String,Set<K>> map = new HashMap();for(TimeUnitEnum timeUnit : TimeUnitEnum.values()) {map.put(timeUnit.name(), primaryCache(timeUnit).asMap().keySet());}return map;}}

RedisSecondaryCache

@Slf4j
@Component
public class RedisSecondaryCache implements SecondaryCache<String>{@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic String getValueFromSecondary(String key){Object redisCache = redisTemplate.opsForValue().get(key);return redisCache == null ? null : redisCache.toString();}@Overridepublic String getValueFromSecondaryBatch(List<String> cacheKeys) {Object redisCache = redisTemplate.opsForValue().multiGet(cacheKeys);return redisCache == null ? null : redisCache.toString();}@Overridepublic <T> void setValueForSecondary(String cacheKey,long expireSeconds, TimeUnit timeUnit, T value) {redisTemplate.opsForValue().set(cacheKey,JSONObject.toJSON(value),expireSeconds, timeUnit);}@Overridepublic <T> void setValueForSecondaryBatch(Map<String, T> kv, long expireSeconds) {kv.forEach((k, v) -> {redisTemplate.opsForValue().set(k, v, expireSeconds, TimeUnit.MINUTES);});}@Overridepublic void invalidate(Object o) {redisTemplate.delete(String.valueOf(o));}@Overridepublic void invalidateAll(List keys) {redisTemplate.delete(keys);}}

CacheContext

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CacheContext<K, T> {K key;Type reference;// 传递函数,Supplier可以把函数作为实参传递,调用Supplier.get()时返回函数的结果Supplier<T> callback;Long expireSeconds;TimeUnit timeUnit;
}

CacheManage

缓存管理接口

-定义

public interface CacheManage<K, V> extends InvalidateCommand {boolean useCache();String cacheKey();Cache<K, V> primaryCache(TimeUnitEnum timeUnit);SecondaryCache secondaryCache();Map<String, Map<String, V>> showAsMap();Map<String,Set<K>> keys();}

SecondaryCache

redis缓存接口类

  • 定义一些接口,比如获取缓存,设置缓存
public interface SecondaryCache<K> extends InvalidateCommand{String getValueFromSecondary(K key);String getValueFromSecondaryBatch(List<K> keys);<T> void setValueForSecondary(K key, long expireSeconds, TimeUnit timeUnit, T value);<T> void setValueForSecondaryBatch( Map<K, T > kv, long expireSeconds);
}

SecondaryCacheFactory

二级缓存工厂类

  • 感觉啥也没干,不知道这个有什么用
public class SecondaryCacheFactory {private SecondaryCacheFactory(){}public static <T> T create(Class<T> clazz) {return (T) SpringContext.me().getBean(clazz);}
}

TimeUnitEnum

/*** 缓存支持的时间的单位* @author*/
public enum TimeUnitEnum {MINUTES(TimeUnit.MINUTES),SECONDS(TimeUnit.SECONDS);@Getterprivate TimeUnit timeUnit;TimeUnitEnum(TimeUnit timeUnit){this.timeUnit = timeUnit;}
}

InvalidateCommand

public interface InvalidateCommand<K> {void invalidate(K k);void invalidateAll(List<K> k);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/635930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python利用Excel读取和存储测试数据完成接口自动化教程

http_request2.py用于发起http请求 #读取多条测试用例#1、导入requests模块import requests#从 class_12_19.do_excel1导入read_data函数from do_excel2 import read_datafrom do_excel2 import write_datafrom do_excel2 import count_case#定义http请求函数COOKIENonedef ht…

Spring Boot Aop 执行顺序

Spring Boot Aop 执行顺序 1. 概述 在 spring boot 项目中&#xff0c;使用 aop 增强&#xff0c;不仅可以很优雅地扩展功能&#xff0c;还可以让一写多用&#xff0c;避免写重复代码&#xff0c;例如&#xff1a;记录接口耗时&#xff0c;记录接口日志&#xff0c;接口权限&…

python 自动化模块 - pyautogui初探

python 自动化模块 - pyautogui 引言一、安装测试二、简单使用三、常用函数总结 引言 在画图软件中使用pyautogui拖动鼠标&#xff0c;画一个螺旋式的正方形 - (源码在下面) PyAutoGUI允许Python脚本控制鼠标和键盘&#xff0c;以自动化与其他应用程序的交互。API的设计非常简…

限流算法之流量控制的平滑之道:滑动时间窗算法

文章目录 引言简介优点缺点样例样例图样例代码 应用场景结论 引言 在互联网应用中&#xff0c;流量控制是一个重要的组件&#xff0c;用于防止系统过载和保护核心资源。常见的限流算法包括固定窗口算法和滑动时间窗算法。本文将重点介绍滑动时间窗算法&#xff0c;并分析其优缺…

基于Abaqus的三种钢筋混凝土梁数值模拟对比研究

混凝土结构抗压强度高&#xff0c;而抗拉强度大约只有其十分之一&#xff0c;在受到竖向荷载&#xff08;包括自重&#xff09;作用下&#xff0c;梁下部会产生拉应力&#xff0c;上部产生压应力&#xff0c;而由于其抗拉强度低&#xff0c;因此很小的荷载即可导致梁下部开裂&a…

Mysql中的日志系统

文章目录 1. 慢查询日志&#xff08;Slow Query Log&#xff09;1.1 是否开启慢查询日志1.2 开启慢查询日志&#xff0c;设置时间阈值1.2.1 修改文件my.ini1.2.2 重启mysql后配置生效 1.3 查看慢查询日志1.3.1 直接用文本编辑器打开1.3.2 使用mysqldumpslow进行分析 2. InnoDB …

C语言从入门到实战——文件操作

文件操作 前言一、 为什么使用文件二、 什么是文件2.1 程序文件2.2 数据文件2.3 文件名 三、 二进制文件和文本文件四、 文件的打开和关闭4.1 流和标准流4.1.1 流4.1.2 标准流 4.2 文件指针4.3 文件的打开和关闭4.4 文件的路径 五、 文件的顺序读写5.1 顺序读写函数介绍fgetcfp…

【音视频原理】图像相关概念 ③ ( RGB 色彩简介 | RGB 排列 | YUV 色彩简介 | YUV 编码好处 )

文章目录 一、RGB 色彩1、RGB 色彩简介2、RGB 排列 二、YUV 色彩1、YUV 色彩简介2、YUV 编码好处 一、RGB 色彩 1、RGB 色彩简介 RGB 是 计算机 中的 颜色编码方法 , 红 ( R ) / 绿 ( G ) / 蓝 ( B ) 三个颜色通道 可以设置不同的值 , 每个 通道 的 颜色值都可以取值 0 ~ 255 ,…

【已解决】namespace “Ui“没有成员 xxx

先说笔者遇到的问题&#xff0c;我创建一个QWidget ui文件&#xff0c;然后编辑的七七八八后&#xff0c;想要用.h与.cpp调用其&#xff0c;编译通过&#xff0c;结果报了这个错误&#xff0c;本方法不是普适性&#xff0c;但是确实解决了这个鸟问题。 问题来源 搭建ui后&…

数据分析师不加班的秘密,三行代码教你Python自动发送邮件

作为一名数据分析师&#xff0c;每天除了做数据日报&#xff0c;还要编写邮件正文和添加数据日报附件&#xff0c;发送给对应的负责人及销售个人&#xff0c;一般一封邮件应包含邮箱账户名、邮箱密码、发送人邮箱、邮件主题以及邮件正文。 本文借助Python工具&#xff0c;使用y…

MyBatis框架基础到进阶

1、为什么要学习MyBatis 如果没有MyBatis框架&#xff0c;我们依靠JDBC和连接池已经能够很好的和数据库进行交互了&#xff0c;而学习MyBatis框架最核心的原因是为了减少SQL语句对代码的侵入性。 因为在过往不管是使用连接池还是JDBC Templete&#xff0c;所有的SQL语句都写在代…

java.sql.SQLException: Failed to fetch schema of XXX 问题

遇到问题&#xff1a;java.sql.SQLException: Failed to fetch schema of pay_record表 i.s.r.d.s.s.c.AbstractTableMetaCache : get table meta of the table pay_record error: Failed to fetch schema of pay_record 原因分析&#xff1a; springcloud项目中使用了se…

上海亚商投顾:沪指冲高回落 旅游板块全天强势

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日冲高回落&#xff0c;创业板指跌近1%&#xff0c;北证50指数跌超3%。旅游、零售板块全天强势&#xf…

python类继承之__init__函数覆盖问题

目录 1.问题描述 2.代码演示 3.总结 在Python这个广受欢迎的编程语言中&#xff0c;类继承是一项强大而精巧的特性。通过类继承&#xff0c;我们可以构建出更加灵活、可重用和易维护的代码&#xff0c;同时实现代码的模块化和扩展性。 但是如果对于熟悉C和java的人而言&…

R语言学习 case2:人口金字塔图

step1&#xff1a;导入库 library(ggplot2) library(ggpol) library(dplyr)step2&#xff1a;读取数据 data <- readxl::read_xlsx("data_new.xlsx", sheet 1) datareadxl::read_xlsx() 是 readxl 包中的函数&#xff0c;用于读取Excel文件。 step3&#xff1…

ckman:非常好用的ClickHouse可视化集群运维工具

概述 什么是ckman ckman&#xff0c;全称是ClickHouse Management Console&#xff0c; 即ClickHouse管理平台。它是由擎创科技数据库团队主导研发的一款用来管理和监控ClickHouse集群的可视化运维工具。目前该工具已在github上开源&#xff0c;开源地址为&#xff1a;github…

全网最详细丨2024年AMC8真题及答案来了

目录 前言 真题回忆 真题解析 结尾 前言 相信大家都已经知道今年AMC8出事情了吧&#xff0c;但最重要的还是要从中学到新知识。 听说今年考生被提前12分钟强制交卷了&#xff0c;肯定因为试题泄露了。 最新回复&#xff1a;我们这边已经退费了 真题回忆 需要word文档的请…

快速幂 算法

暴力算法 我们可以采用暴力算法 #include<bits/stdc.h> using namespace std; #define ll long long int main() {ll a, b, c;cin >> a >> b >> c;ll ans 1;for (ll i 1; i < b; i) {ans * a;}ans % c;cout << ans; } 不过这样肯定会超时…

计算机网络基础概念解释

1. 什么是网络 随着时代的发展&#xff0c;越来越需要计算机之间互相通信&#xff0c;共享软件和数据&#xff0c;即以多个计算机协同⼯作来完成业务&#xff0c;于是有了网络互连。 网络互连&#xff1a;将多台计算机连接在⼀起&#xff0c;完成数据共享。 数据共享本质是网络…

「 网络安全常用术语解读 」杀链Kill Chain详解

1. 简介 早在2009年&#xff0c;Lockheed Martin公司就提出了杀链(Kill Chain)理论&#xff0c;现在也称之为攻击者杀链(Attacker Kill Chain)。杀链其实就是攻击者进行网络攻击时所采取的步骤。杀链模型包括7个步骤&#xff1a;1侦察 -> 2武器化 -> 3交付 -> 4利用 …