@Cacheable缓存相关使用总结
本篇文章主要讲解Spring当中@Cacheable缓存相关使用
在实际项目开发中,有些数据是变更频率比较低,但是查询频率比较高的,此时为了提升系统性能,可以使用缓存的机制实现,避免每次从数据库获取
第一步:使用@EnableCaching注解开启缓存
开启缓存功能,配置类中需要加上这个注解,有了这个注解之后,spring才知道你需要使用缓存的功能,其他和缓存相关的注解才会有效,Spring中主要是通过aop实现的,通过aop来拦截需要使用缓存的方法,实现缓存的功能
第二步:在方法或类上添加@Cacheable注解,表明某一个方法或者某一个类里的所有方法开启缓存功能;
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。
对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的(因为是Aop实现的,Aop是核心是代理,内部调用无法被代理,也就不会生效)。@Cacheable可以指定三个属性,value、key和condition。
测试相关的类如下:ArticleService主要是提供模拟缓存的接口
package com.ym.example.demo.cachable;import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Component;import java.util.*;@Component
public class ArticleService {private Map<Long, String> articleMap = new HashMap<>();@Cacheable(cacheNames = {"cacheTest"})public List<String> list(){System.out.println("获取文章列表");return Arrays.asList("Spring", "MySQL", "java高并发", "Maven");}@Cacheable(value = {"cacheTest"})public List<String> listValue(){System.out.println("获取文章列表");return Arrays.asList("Spring", "MySQL", "java高并发", "Maven");}/*** @Author yangming* @Description* @Cacheable可以标记在方法上,也可以标记在一个类上,当标记在一个方法上是,表示该方法时支持缓存的,当标记到一个类上时,则表示该类所有的方法都是支持缓存的* 对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。* Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略* 这里需要注意,因为Spring缓存是通过aop实现的,aop又是依赖的代理模式,所以当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的* value和cacheNames一样,都是指定缓存的名称,这个cache名称可以是一个,也可以是多个,需要指定多个cache时其是一个数组* 可以将Cache理解为一个HashMap,系统中可以有很多歌Cache,每个Cache都有一个名字,你需要将方法的返回值放在哪个缓存中,需要通过缓存的名称来指定* key属性用来指定Spring缓存方法的返回结果时对应的key,因为Cache可以理解为一个HashMap,缓存以key-value的形式存储在HashMap中,value就是需要缓存的值(即方法返回值)* key属性支持spel表达式,当我们没有指定该属性时,Spring将使用默认策略生成key(org.springframework.cache.interceptor.SimpleKeyGenerator),默认会以方法参数创建key* 自定义策略是指我们可以通过SpEL表达式来指定我们的key,这里的SpEL表达式可以使用方法参数及他们对应的属性,使用方法参数时我们可以直接使用"#参数名"或者"#p参数index"* Spring还未我们提供了一个root对象可以用来生成key,通过该root对象我们可以获取到以下信息* methodName 当前方法名 #root.methodName* method 当前方法 #root.method.name* target 当前被调用的对象 #root.target* targetClass 当前被调用的对象的class #root.targetClass* args 当前方法参数组成的数组 #root.args[0]* caches 当前被调用的方法使用的cache #root.caches[0].name** @Date 2023/8/12 10:36* @param page* @param pageSize**/@Cacheable(value = {"cacheTest"}, key = "#root.target.class.name+'-'+#page+'-'+#pageSize")public String getPage(int page, int pageSize){String msg = String.format("page-%s-pageSize-%s", page, pageSize);System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 没有指定key。默认为方法参数创建key,该方法的key为SimpleKey [1,10]* @Date 2023/8/12 10:55* @param page* @param pageSize**/@Cacheable(value = {"cacheTest"})public String getPageKey(int page, int pageSize){String msg = String.format("page-%s-pageSize-%s", page, pageSize);System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 没有指定key。默认为方法参数创建key,该方法的key为SimpleKey []* @Date 2023/8/12 10:55**/@Cacheable(value = {"cacheTest"})public String getPageKey(){String msg = "测试key";System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 有时候希望方法调用走缓存,有时候不希望走缓存,condition为true表示先尝试从缓存中取,如果缓存中没有,则执行方法,并将方法返回结果放到缓存中,* condition为false表示不走缓存,直接执行方法,并且返回的结果也不会放到缓存中* @Date 2023/8/11 19:39* @param id* @param cache**/@Cacheable(cacheNames = "cacheTest", key="'getById'+#id", condition = "#cache")public String getById(Long id, boolean cache){System.out.println("getById获取数据!");return "Spring缓存: " + UUID.randomUUID().toString();}/*** @Author yangming* @Description 当condition为空或者为true的情况下,unless才有效,condition为false的时候,unless无效,* unless为true,表示方法防结果不放到缓存中,unless为false,表示方法返回结果要放到缓存中* condition和unless对比* 缓存的使用过程中有两个点:* 1、查询缓存中是否有数据;* 2、如果缓存中没有数据,则去执行目标方法,然后将方法结果放到缓存中* Spring中通过condition和unless对这2点进行干预* condition作用在上面2个点的过程中,当为true的时候,会尝试从缓存中获取数据,如果没有,会执行方法,然后将方法返回值丢到缓存中;* 当为false的时候,则直接调用目标方法,并且结果不会放到缓存中* unless在condition为true的时候才有效,用来判断上面的第2点,看要不要将执行结果放到缓存中,* 如果为true,表示执行的结果不放到缓存中,* 如果为false,表示执行的结果要放到缓存中,在unless中可以使用spel表达式通过#result来获取方法返回值* @Date 2023/8/11 19:50* @param id**/@Cacheable(cacheNames = "cacheTest", key = "'findById'+#id", unless = "#result==null")public String findById(Long id){this.articleMap.put(1L, "Spring系列");System.out.println("-----获取文章: " + id + "-------");return this.articleMap.get(id);}/*** @Author yangming* @Description @CachePut也可以标注在类或者方法上,被标注的方法每次都会被调用,然后方法执行完毕之后,会将方法结果放到缓存中;当标注在类上,相当于在类的所有方法上都标注了@CachePut* @CachePut有3种情况,结果不会放到缓存* 1、当方法向外抛出异常的时候* 2、当condition的计算结果为false的时候* 3、unless的计算结果为true的时候* value,cacheNames,key,condition,unless的用法和@Cacheable中类似* @Date 2023/8/12 11:05* @param id* @param content**/@CachePut(cacheNames = "cacheTest", key = "'findById'+#id")public String add(Long id, String content){System.out.println("新增文章: " + id);this.articleMap.put(id, content);return content;}/*** @Author yangming* @Description @CacheEvict是用来清除缓存的,可以标注在类或者方法上,被标注在方法上,则目标方法被调用的时候,会清除指定的缓存;当标注在类上,相当于在类的所有方法上标注了@CacheEvict* value,cacheNames,key,condition的用法和@Cacheable中类似,@CacheEvict多了allEntries和beforeInvocation属性* allEntries:表示是否清理cacheNames指定的缓存中的所有缓存信息,默认为false* 可以将cache理解为一个HashMap,当allEntries为true的时候,相当于HashMap.clear(),* 当allEntries为false的时候,只会干掉key对应的数据,相当于HashMap.remove(key)* beforeInvocation:表示何时执行清除操作(方法执行前 or 方法执行成功之后)* true:表示@CacheEvict 标注的方法执行之前,执行清除操作* false:表示@CacheEvict 标注的方法执行成功之后,执行清除操作,当方法弹出异常的时候,不会执行清除操作* @Date 2023/8/12 11:25* @param id**/@CacheEvict(cacheNames = "cacheTest", key = "'findById'+#id")public void delete(Long id){System.out.println("根据id删除文章: " + id);this.articleMap.remove(id);}@Caching(cacheable = {@Cacheable(value = "cacheTest", key="#root.methodName")},put={@CachePut(value = "cacheTest", key = "#root.methodName")})public void testCaching(){}
}
CacheConfig提供缓存相关的配置,这个CacheMangager有多种实现,本例是使用的ConcurrentMapCacheManager实现,也可以是RedisCacheManager的实现
package com.ym.example.demo.cachable;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** @author yangming* @date 2023/8/11 19:24* @desc @EnableCaching表示开启缓存,有了这个注解之后,Spring才知道你需要使用缓存的功能,其他和缓存相关的注解才会生效* Spring中主要是通过aop实现的,通过aop来拦截需要使用缓存的方法,实现缓存的功能* @package com.ym.example.demo.cachable*/
@EnableCaching
@ComponentScan
@Configuration
public class CacheConfig {/*** @Author yangming* @Description 开启缓存之后,还需要在配置类中定义一个bean,作为缓存管理器,类型为CacheManager,* CacheManager是一个接口,有好几个实现,比如使用redis,ConcurrentMap为存储缓存信息,* 本例使用的是ConcurrentMapCacheManager,内部使用ConcurrentHashMap将缓存信息直接存储在本地jvm内存中* 不过线上环境一般是集群的方式,可以通过redis实现* @Date 2023/8/12 10:45**/@Beanpublic CacheManager cacheManager(){ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager("cacheTest");return cacheManager;}
}
CacheTest是测试相关的方法
package com.ym.example.demo.cachable;import org.junit.Test;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** @author yangming* @date 2023/8/11 19:26* @package com.ym.example.demo.cachable*/
public class CacheTest {@Testpublic void test(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);System.out.println(articleService.list());System.out.println(articleService.list());}执行结果:获取文章列表[Spring, MySQL, java高并发, Maven][Spring, MySQL, java高并发, Maven]@Testpublic void test1(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//page=1,pageSize=10调用2次System.out.println(articleService.getPage(2, 10));System.out.println(articleService.getPage(2, 10));//page=2,pageSize=10调用2次System.out.println(articleService.getPage(3, 10));System.out.println(articleService.getPage(3, 10));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:从db中获取数据: page-2-pageSize-10page-2-pageSize-10page-2-pageSize-10从db中获取数据: page-3-pageSize-10page-3-pageSize-10page-3-pageSize-10下面打印出cacheTest缓存中的key列表com.ym.example.demo.cachable.ArticleService-3-10com.ym.example.demo.cachable.ArticleService-2-10@Testpublic void test2(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次,缓存中没有,执行方法,将结果放到缓存System.out.println(articleService.getById(1L, true));//第二次,缓存中有,直接从缓存中获取System.out.println(articleService.getById(1L, true));//第三次,condition为false,表示不从缓存取,直接执行方法,同时方法执行结果也不放到缓存System.out.println(articleService.getById(1L, false));//第四次,condition为true,缓存有,直接从缓存中取System.out.println(articleService.getById(1L, true));}执行结果:getById获取数据!Spring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08Spring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08getById获取数据!Spring缓存: 7ff6c668-87f1-4432-8844-61bf66b6e3efSpring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08@Testpublic void test3(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次,没有缓存,执行方法,unless为false,表示执行结果要放到缓存中System.out.println(articleService.findById(1L));//第二次,第一次之后,缓存有数据,直接从缓存中取数据System.out.println(articleService.findById(1L));//第三次,缓存中没有,执行方法,result==null,unless为true,表示执行结果不放到缓存中System.out.println(articleService.findById(2L));//第四次,为了验证第三次的结论System.out.println(articleService.findById(2L));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:-----获取文章: 1-------Spring系列Spring系列-----获取文章: 2-------null-----获取文章: 2-------null下面打印出cacheTest缓存中的key列表findById1@Testpublic void test4(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);articleService.getPageKey(1,10);articleService.getPageKey();{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:从db中获取数据: page-1-pageSize-10从db中获取数据: 测试key下面打印出cacheTest缓存中的key列表SimpleKey []SimpleKey [1,10]@Testpublic void test5(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//增加2个文章,由于add方法上有@CachePut注解,所以新增之后会自动丢到缓存中articleService.add(1L, "java高并发系列");articleService.add(2L, "MySQL高手系列");//然后调用findById获取,看看是否会走缓存System.out.println("调用findById方法,会尝试从缓存中获取");System.out.println(articleService.findById(1L));System.out.println(articleService.findById(2L));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:新增文章: 1新增文章: 2调用findById方法,会尝试从缓存中获取java高并发系列MySQL高手系列下面打印出cacheTest缓存中的key列表findById2findById1@Testpublic void test6(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次调用findById,缓存中没有,则调用方法,将结果丢到缓存中System.out.println(articleService.findById(1L));//第二次调用findById,缓存存在,直接从缓存中取System.out.println(articleService.findById(1L));//执行删除操作,delete方法上加了@CacheEvict注解,会清除缓存articleService.delete(1L);//再次调用findById方法,缓存中没有了,则会调用目标方法System.out.println(articleService.findById(1L));}执行结果:-----获取文章: 1-------Spring系列Spring系列根据id删除文章: 1-----获取文章: 1-------Spring系列
}
@Caching:缓存注解组
当我们在类上或者同一个方法上同时使用@Cacheable、@CachePut和@CacheEvic这几个注解中的多个的时候,此时可以使用@Caching这个注解来实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
Cacheable[] cacheable() default {};
CachePut[] put() default {};
CacheEvict[] evict() default {};
}
@CacheConfig:提取公共配置
这个注解标注在类上,可以将其他几个缓存注解(@Cacheable、@CachePut和@CacheEvic)的公共参数给提取出来放在@CacheConfig中。比如当一个类中有很多方法都需要使用(@Cacheable、@CachePut和@CacheEvic)这些缓存注解的时候,大家可以看一下这3个注解的源码,他们有很多公共的属性,比如:cacheNames、keyGenerator、cacheManager、cacheResolver,若这些属性值都是一样的,可以将其提取出来,放在@CacheConfig中,不过这些注解(@Cacheable、@CachePut和@CacheEvic)中也可以指定属性的值对@CacheConfig中的属性值进行覆盖。
@CacheConfig(cacheNames = "cache1")
public class ArticleService {@Cacheable(key = "'findById'+#id")public String findById(Long id) {this.articleMap.put(1L, "spring系列");System.out.println("----获取文章:" + id);return articleMap.get(id);}
}
spring中的缓存主要是利用spring中aop实现的,通过Aop对需要使用缓存的bean创建代理对象,通过代理对象拦截目标方法的执行,实现缓存功能。重点在于 @EnableCaching 这个注解,可以从 @Import 这个注解看起
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {}
最终会给需要使用缓存的bean创建代理对象,并且会在代理中添加一个拦截器
org.springframework.cache.interceptor.CacheInterceptor ,这个类中的 invoke 方法是关键,
会拦截所有缓存相关的目标方法的执行,有兴趣可以去细看一下。
相关文章:
@Cacheable缓存相关使用总结
本篇文章主要讲解Spring当中Cacheable缓存相关使用 在实际项目开发中,有些数据是变更频率比较低,但是查询频率比较高的,此时为了提升系统性能,可以使用缓存的机制实现,避免每次从数据库获取 第一步:使用E…...
c++ static
static 成员 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。 看看下面代码体会一下: //其他类 class …...
【数据结构】——栈、队列的相关习题
目录 题型一(栈与队列的基本概念)题型二(栈与队列的综合)题型三(循环队列的判空与判满)题型四(循环链表表示队列)题型五(循环队列的存储)题型六(循…...
C++初阶之一篇文章教会你list(模拟实现)
list(模拟实现) list模拟实现list_node节点结构定义std::__reverse_iterator逆向迭代器实现list迭代器 __list_iterator定义list类成员定义list成员函数定义1.begin()、end()、rbegin()和rend()2.empty_init()3.构造函数定义4.swap5.析构函数定义6.clear…...
设备工单管理系统如何实现工单流程自动化?
设备工单管理系统属于工单系统的一种,基于其丰富的功能,它可以同时处理不同的多组流程,旨在有效处理发起人提交的事情,指派相应人员完成服务请求和记录全流程。该系统主要面向后勤管理、设备维护、物业管理、酒店民宿等服务行业设…...
ubuntu20.04.6anzhuang mtt s80
需要打开主板的Resize BAR和Above 4G功能,否则GPU显存不能被正确识别; 2. 在某些不支持PCIe Gen5的主板上,需要把PCIe速率由auto设置为PCIe Gen4速率; sudo apt install lightdm unity-greetersheding lightdm : lightdm sudo apt install /…...
【LeetCode-中等】剑指 Offer 36. 二叉搜索树与双向链表
题目链接 剑指 Offer 36. 二叉搜索树与双向链表 标签 后序遍历、二叉搜索树 步骤 二叉搜索树中的任一节点的直接前驱为其左子树的最右侧节点,直接后继为其右子树的最左侧节点。因此,可以通过这个关系来操作原来的二叉树。为了不影响深度较大的节点的…...
Linux —— 文件系统
目录 一,背景 二,文件系统 一,磁盘简介 磁盘分为SSD、机械磁盘;机械磁盘,即磁盘高速转动,磁头移动到读写扇区所在磁道,让磁头在目标扇区上划过,即可完成对扇区的读写操作ÿ…...
自然策略优化的解释 Natural Policy Optimization
Natural Policy Optimization(自然策略优化)是一种用于优化策略梯度算法的方法。它是基于概率策略的强化学习算法,旨在通过迭代地更新策略参数来最大化累积回报。 传统的策略梯度算法通常使用梯度上升法来更新策略参数,但这种方法…...
docker基本使用方法
docker使用 1. Docker 介绍 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。通过利用 …...
机器学习(十八):Bagging和随机森林
全文共10000余字,预计阅读时间约30~40分钟 | 满满干货(附数据及代码),建议收藏! 本文目标:理解什么是集成学习,明确Bagging算法的过程,熟悉随机森林算法的原理及其在Sklearn中的各参数定义和使用方法 代码…...
使用蓝牙外设却不小心把台式机电脑蓝牙关了
起因 今天犯了一个贼SB的错误,起因是蓝牙键盘突然就不能输入了(虽然是连接状态,但是按什么键都没有反应) 原来我的解决方法就是重启一下电脑,但是那会电脑开了贼多的软件。我就想重启也太麻烦了,既然重启…...
美国Linux服务器安装Grafana和配置zabbix数据源的教程
美国Linux服务器的Grafana工具是跨平台、开源、时序和可视化面板Dashboard监控平台工具,是在日常管理中帮忙提高效率的实用工具,可以通过将采集的美国Linux服务器系统数据查询后,进行可视化的展示及通知,本文小编就来介绍下美国Li…...
[ROS安装问题] rosdep update 失败报错
【关于ROS安装】 由于日益复杂的国际形势,按照wiki官网的ROS安装流程变得相当困难,这里我推荐使用鱼香ROS大佬写的脚本一键傻瓜式安装: wget http://fishros.com/install -O fishros && . fishros 【关于rosdep失败】 这已经是一…...
Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)
简介: Vue2到3 Day1-3 全套学习内容,众多案例上手(内付源码)_星辰大海1412的博客-CSDN博客本文是一篇入门级的Vue.js介绍文章,旨在帮助读者了解Vue.js框架的基本概念和核心功能。Vue.js是一款流行的JavaScript前端框架…...
STM32 CubeMX (uart_IAP串口)简单示例
STM32 CubeMX STM32 CubeMX (串口IAP) STM32 CubeMXIAP有什么用?整体思路 一、STM32 CubeMX 设置时钟树UART使能UART初始化设置 二、代码部分文件移植 topic:Kafka将消息分门别类,每一个消息称为一个主题(topic) consumer:订阅消息并处理发布消息的对象…...
786. 第k个数
文章目录 QuestionIdeasCode Question 给定一个长度为 n 的整数数列,以及一个整数 k ,请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k 。 第二行包含 n 个整数(所有整数均在 1∼109 范围内&…...
用友-NC-Cloud远程代码执行漏洞[2023-HW]
用友-NC-Cloud远程代码执行漏洞[2023-HW] 一、漏洞介绍二、资产搜索三、漏洞复现PoC小龙POC检测脚本: 四、修复建议 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#…...
Transformer(二)(VIT,TNT)(基于视觉CV)
目录 1.视觉中的Attention 2.VIT框架(图像分类,不需要decoder) 2.1整体框架 2.2.CNN和Transformer遇到的问题 2.3.1CNN 2.3.2Transformer 2.3.3二者对比 2.4.公式理解 3TNT 参考文献 1.视觉中的Attention 对于人类而言看到一幅图可以立…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
