深入SpringBoot:SpringCache的集成与使用

news2024/11/24 2:20:25

目录

  • 一、SpringCache集成
    • 声明式与编程式
      • 1. 引入依赖
      • 2. SpringCache配置
      • 3. key的设置
      • 4. 使用
  • 二、SpringCache使用
    • 1. 基于声明式注释的缓存
    • 1.1 @Cacheable注解
    • 1.2 @Cacheable注解属性
      • 1.2.1 CacheManager和CacheResolver
      • 1.2.2 cacheName
      • 1.2.3 key和KeyGenerator
      • 1.2.4 同步缓存
    • 2. 条件缓存
      • 2.1 @CachePut注解
      • 2.2 @CacheEvict注解
      • 2.3 Caching注解
      • 2.4 CacheConfig注解

一、SpringCache集成

声明式与编程式

说起SpringCache您可能不清楚。但您绝对清楚事务。一般使用事务分为编程式和声明式。

  • 编程式:事务操作与业务代码耦合,一般我们不会使用这种方式;
  • 声明式:AOP的运用,通过注解使得事务代码与业务代码解耦,目前项目中一般都是使用事务注解。

而我们平时使用缓存,正是编程式,即对缓存的操作与业务代码耦合。那么是否存在一种类似于事务的技术,完成声明式的缓存操作呢?

而SpringCahe便可以提供透明化的缓存操作,即用户可以使用注解的方式。灵活的操纵缓存。

1. 引入依赖

本篇是SpringCache+Redis的整合。SpringCache只是缓存抽象,即具体缓存的操作需要子类实现。

spring-boot-starter-data-redis中实现了SpringCache的抽象接口,即我们整合SpringCache+Redis无需自己实现具体缓存。

        <!--SpringCache的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
       <!--整合Redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

SpringBoot2.X整合Redis缓存可以看这篇文章,因为有个项目在生产环境中,使用lettuce客户端每隔一段时间连接断开(初步估计是Redis机房和应用服务器机房网络问题)。切换成了jedis客户端。

2. SpringCache配置

两种配置,一种可以在yml中配置,一种是在代码中配置,此处推荐在@Configuration中进行配置。

原因一是更加灵活,在配置CacheManager的Bean时,可以初始化Cache对象,在项目启动的时候注册到CacheManager中。

import com.galax.Config.serialize.RedisObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableCaching  //开启缓存,可以放在启动类上。
public class RedisSpringCache {

    /**
     * 自定义KeyGenerator。
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            //获取代理对象的最终目标对象
            Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
            StringBuilder sb = new StringBuilder();
            sb.append(targetClass.getSimpleName()).append(":");
            sb.append(method.getName()).append(":");
            //调用SimpleKey的逻辑
            Object key = SimpleKeyGenerator.generateKey(params);
            return sb.append(key);
        };
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        //设置特有的Redis配置
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
        //定制化的Cache为300s
        cacheConfigurations.put("as",customRedisCacheConfiguration(Duration.ofSeconds(300)));
        cacheConfigurations.put("books",customRedisCacheConfiguration(Duration.ofSeconds(300)));
        cacheConfigurations.put("cs",customRedisCacheConfiguration(Duration.ofSeconds(300)));
        //默认超时时间60s
        return RedisCacheManager.builder(connectionFactory).
                transactionAware().   //Cache的事务支持
                cacheDefaults(customRedisCacheConfiguration(Duration.ofSeconds(60))).
                withInitialCacheConfigurations(cacheConfigurations).   //设置个性化的Cache配置
                build();
    }


    /**
     * 设置RedisConfiguration配置
     *
     * @param ttl
     * @return
     */
    public RedisCacheConfiguration customRedisCacheConfiguration(Duration ttl) {
        //设置序列化格式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer
                = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(RedisObjectMapper.redisConfigurationObjectMapper());
        return RedisCacheConfiguration.
                defaultCacheConfig().serializeValuesWith(
                RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).
                computePrefixWith(cacheName -> cacheName + ":").   //设置Cache的前缀,默认::
                disableCachingNullValues().   //若返回值为null,则不允许存储到Cache中
                entryTtl(ttl);  //设置缓存缺省超时时间
    }
}

注意不要将ObjectMapper加入到Spring容器中。因为Spring容器中存在一个ObjectMapper,以用于@RequestBodyResponseBodyRestTemplate等地的序列化和反序列化。

为什么不采用Spring容器的ObjectMapper对象,而要自己设置是因为Redis配置了objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);属性,在序列化时记录类/属性的类型,以便在反序列化时得到POJO对象。

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class RedisObjectMapper {

    public static ObjectMapper redisConfigurationObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        //JDK1.8新版时间格式化Model
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        objectMapper.registerModule(javaTimeModule);
        //Date类型禁止转换为时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        //序列化时格式化时间戳
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //字段名字开启驼峰命名法
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        //序列化无public的属性或方法时,不会抛出异常
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //序列化时保存对象类型,以便反序列化时直接得到具体POJO
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        //非空数据才进行格式化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //针对BigDecimal,序列化时,不采取科学计数法
        objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        //反序列化时,POJO中不含有JSON串的属性,不解析该字段,并且不会抛出异常
        objectMapper.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        //反序列化{}时,不抛出异常,而是得到null值
        objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        return objectMapper;
    }
}

此处可以使用protostuff替换Jackson进行序列化和反序列化,详细内容请点击…

3. key的设置

需要注意的是,SpringCache作为应用层的声明式缓存。其数据结构为Key-Value。那么设计一个安全优雅的Key,是一个重要的任务。

  1. 在SpringCache官网中,这样描述SpringCache默认的KeyGenerator的:
  • 若没有参数值被得到,返回SimpleKey.EMPTY(空数组)。
  • 若只有一个参数值被得到,返回该参数值的实例。
  • 若多个参数值被得到,返回一个包含所有参数值SimpleKey对象。
  1. 默认的KeyGenerator如何获取参数值?
  • 若注解上只是指定cacheName属性,SimpleKeyGenerator将获取所有的参数值。组成SimpleKey对象。
  • 指定cacheNamekey属性,并且key的属性支持SpEL表达式:
    1.基本形式
@Cacheable(value="cacheName", key="#id")
public ResultDTO method(int id);

2.组合形式

@Cacheable(value="cacheName", key="T(String).valueOf(#name).concat('-').concat(#password))
public ResultDTO method(int name, String password);

3.对象形式

@Cacheable(value="cacheName", key="#user.id)
public ResultDTO method(User user);
  1. 默认的SimpleKeyGenerator的缺陷

SimpleGenerator只会将参数值封装为SimpleKey对象。然后作为Key,可能会导致不同方法Key冲突。
我们虽然可以使用SpEL表达式获取类名、方法名,在进行拼接。但是需要为每一个注解指定,太过于繁杂。

  1. 自定义KeyGenerator

注解上keyGenerator属性与key属性是不共存的,即我们若通过keyGenerator来自定义我们的Key生成器,那么就需要将所有的参数值均进行处理,而不能指定特定的参数值
处理。

    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            //获取代理对象的最终目标对象
            Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
            StringBuilder sb = new StringBuilder();
            sb.append(targetClass.getSimpleName()).append(":");
            sb.append(method.getName()).append(":");
            //调用SimpleKey的逻辑
            Object key = SimpleKeyGenerator.generateKey(params);
            return sb.append(key);
        };
    }

使用:

    @Cacheable(value = "book2",keyGenerator = "keyGenerator")
    public Account getAccInfo(String customerId, String accType) {
      //业务逻辑
    }

4. 使用

springCache和事务类型,均采用AOP原理。故它们的注意事项也是相同。

1.若一个service中,注解方法被调用,则注解不会生效;
2.只有访问修饰符为public的方法,注解才会生效;

二、SpringCache使用

在Spring3.1版本后,Spring框架提供了对缓存透明化应用的支持。缓存抽象允许使用各种缓存解决方案,而对代码的影响最小。

从Spring4.1开始,通过支持JSR-107注释和更多自定义选项,来改善缓存抽象。

1. 基于声明式注释的缓存

SpringCache是Service层的声明式缓存。即无需与业务代码耦合,通过注解完成缓存。

1.1 @Cacheable注解

@Cacheable的注解的处理流程如下图:
image

可以使用@Cacheable用来划分可缓存的方法,即将结果存储在缓存中的方法,以便在后续调用(使用相同的参数)时,返回缓存中的值而无需实际执行该方法。

  • 注释声明以最简单的形式:注解属性为CacheName。
@Cacheable("books")
public Book findBook(ISBN isbn) {...}
  • 支持多个CacheName。
@Cacheable({"books", "isbns"})
public Book findBook(ISBN isbn) {...}

1.2 @Cacheable注解属性

调用者在调用方法时,会通过注解属性自动的去缓存中进行查询。那么我们需要指定cacheManager(CacheResolver)cacheNamekey(keyGenerator),来确定去那个缓存管理器(Redis,ConcurrentHashMap等)进行查询。而cacheName以及key会组装成对应的键。

1.2.1 CacheManager和CacheResolver

  1. @CacheManager:对于使用多个缓存管理器的应用程序,可以设置cacheMananger用于选择哪种缓存管理器(redis,EhCache…),非必需,当有多个才需要指定。
@Cacheable(cacheNames="books", cacheManager="anotherCacheManager") 
public Book findBook(ISBN isbn) {...}
  1. @CacheResolver:也可指定使用哪个缓存管理器。需要通过实现org.springframework.cache.interceptor.CacheResolver接口来解析
@Cacheable(cacheResolver="runtimeCacheResolver") 
public Book findBook(ISBN isbn) {...}

cacheManager和cacheResolver参数是互斥的,同时指定这两个参数会导致异常。因为实现CacheManager会忽略自定义的CacheResolver。

1.2.2 cacheName

CacheName属性也是value属性,定义@Cacheable注解时,必须使用该属性。即指定缓存的名字。使用默认CacheManager属性,以及使用默认的key属性(SimpleKey对象包含所有的参数值)。

1.2.3 key和KeyGenerator

  1. keyGenrator属性

SpringCache默认使用SimpleKeyGenerator,默认情况下将参数值作为键,但是可能会导致key重复出现。

我们在整合SpringCache中自定义CacheGenerator,将类名:方法名作为key的一部分。

而后@Cacheable注解中,指定自定义的KeyGenerator。

    @Cacheable(value = "book2",keyGenerator = "keyGenerator")
    public Account getAccInfo(String customerId, String accType) {
      //业务逻辑
    }

注意key和keyGenerator依旧是互斥的。

  1. key属性

当然若是使用key属性,也是可以指定类名和方法名等参数作为key。

SpringCache提供了与缓存相关的专用元数据,例如参数名称。下表描述了可用于上下文的项目,以便于key的生成和条件计算

名称位置描述例子
methodMameroot被调用方法的名称#root.methodName
methodroot被调用的方法#root.method.name
targetroot被调用的目标对象#root.target
targetClassroot被调用目标的类#root.targetClass
argsroot用于被调用目标的参数值(数组)#root.args[0]
cachesroot执行当前方法缓存的集合#root.caches[0].name
参数名称调用的方法方法的任何参数名称#iban或#a0
result调用的方法仅用在unless,方法调用的结果(缓存值)#result
  1. cacheName无法使用SpEL表达式,#root.args是参数值。
    @Cacheable(cacheNames = "#root.methodName",key = "#root.args")
    public User getUser(int id) {
        User user = new User().setUserName("tom").setId(id);
        log.info("【调用getUser】方法");
        return user;
    }

image
图4- @Cacheable(cacheNames = “#root.methodName”,key = “#root.args”).png

  1. 两个SpEL表达式拼接,创建更具体的key值
    @Cacheable(value = "book2",  
            key = "#root.targetClass.getSimpleName().concat(':').concat(#root.methodName).concat(':').concat(#customerId)")  
    public User getUser(int id) {
        User user = new User().setUserName("tom").setId(id);
        log.info("【调用getUser】方法");
        return user;
    }

image
图5-两个SpEL表达式拼接.png

1.2.4 同步缓存

在多线程环境下,某些操作可能会为一个参数并发调用。默认情况下,SpringCache不会锁定任何内容,并且可能多次计算相同的值,从而破坏了缓存的目的。

对于那些特殊情况,可以使用sync属性来锁定。即只有一个线程正在忙于计算该值,而其他线程则被阻塞,直到缓存中更新该条目为止。

@Cacheable(cacheNames="foos", sync=true) 
public Foo executeExpensiveOperation(String id) {...}

2. 条件缓存

  1. condition:方法可能不总适合缓存(例如:他可能取决于给你定的参数)。缓存注释通过condition支持这种功能,该参数采用SpEL表达式,该表达式的值等于true或false。如果为true,则缓存该方法。否则的话,每次调用该方法。例如:仅当参数name的长度小于32时才缓存以下方法:
@Cacheable(cacheNames="book", condition="#name.length() < 32") 
public Book findBook(String name)
  1. unless(如果不):可以使用unless参数来决定是否将值添加到缓存中,该参数也采用SpEl表达式,该表达式输出结果boolean类型。与condition不同的是,unless表达式是在调用方法后求值的,并且当SpEL返回false时,加入到缓存中(unless:如果不小于1000,则存储。)。
    @Cacheable(cacheNames="books", key="#isbn.rawNumber",unless ="#result.id < 1000" )
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) {
        log.info("执行方法!");
        Book book = Book.builder().id(1101).bookName("java").build();
        return book;
    }

SpringCache支持java.util.Optional,仅在支持时才将其内容作为缓存。#result始终引用业务实体,而不引用受支持的包装器。因此可以重写为下面代码:

    @Cacheable(cacheNames="books", key="#isbn.rawNumber",unless ="#result?.id >1000" )
    public Optional<Book> findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) {
        log.info("执行方法!");
        Book book = Book.builder().id(111).bookName("java").build();
        Optional<Book> optionalBook = Optional.of(book);
        return optionalBook;
    }

注意:result仍然指的是Book而不是Optional。

2.1 @CachePut注解

在不影响方法执行的情况下更新缓存,可以使用@CachePut注解。也就是说,该方法始终执行,将其结果放入缓存(根据@CachePut选项)。他支持与@Cacheable缓存相同的属性。但是它应用于缓存填充而不是方法优化。

@CachePut(cacheNames="book", key="#isbn")
public Book updateBook(ISBN isbn, BookDescriptor descriptor)

image
图1-更新缓存.png

2.2 @CacheEvict注解

Spring Cache不仅允许缓存的填充,还允许删除缓存。此过程对于从缓存中删除陈旧或未使用的数据很有用,相对于@Cacheable,@CacheEvict是从缓存中删除数据的注解。@CacheEvict需要指定一个或多个受操作影响的缓存,允许自定义缓存和Key或者条件。

  1. allEntries,该参数指示是否需要在整个缓存范围内逐出而不仅仅是基于Key的逐条逐出。
    代码1:逐出books缓存中的所有条目。
@CacheEvict(cacheNames="books", allEntries=true) 
public void loadBooks(InputStream batch)
  1. beforeInvocation,该参数指定逐出缓存是在方法执行前还是方法执行后(默认方法执行后)。在默认情况下,如果方法未执行(可能已经被缓存)或者引发异常,缓存是不会被移除的。而beforeInvocation=true逐出缓存则是在方法调用前发生。适用于移除操作和方法结果没有必要联系的情况。
    代码2:方法执行前移除缓存
    @CacheEvict(cacheNames = "books", key = "#isbn",beforeInvocation = true)
    public void loadBooks(ISBN isbn) {
        log.info("清除缓存!");
        //出现异常,默认不会清除缓存
        throw new RuntimeException("aa");
    }

注:void方法可以与@CacheEvict一起使用,因为方法充当触发器,返回值将被忽略(因为他们不与缓存交互)。

2.3 Caching注解

指定多个相同类型的注解时(例如@CacheEvict或@CachePut)。因为Key或Key的表达式在不同的缓存间是不同的。@Caching允许嵌套多个@Cacheable,@CachePut和@CacheEvict注解来使用。

代码3:使用两个@CacheEvict注解

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)

2.4 CacheConfig注解

@CacheConfig是一个类级别的注解,他允许共享cacheNames,custom KeyGenerator,custom CacheManager和custom CacheResolver。将此注解注释在类上不会打开任何缓存操作。

注:方法级别的注解会覆盖类注解

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

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

相关文章

Linux 内核源码分析---处理 VFS 对象及标准函数

处理VFS对象 注册文件系统&#xff1a;在文件系统注册到内核时&#xff0c;文件系统是编译为模块&#xff0c;或者持久编译到内核中。 fs/super.c 中的register_filesystem用来向内核注册文件系统。我们可以通过/proc/filesystems查看系统所有的文件系统类型。 一个文件系统不…

Idea绿色下载安装教程-最新,2024版本通用-附下载链接

插件链接&#xff1a; 脚本 Idea下载安装完成后 进入激活码输入页面&#xff0c;然后关闭IDEA 按照下面流程进行激活 1. 按照以下步骤&#xff0c;亲测可用&#xff0c;记得一定要先关闭idea 2. 选择对应软件 3.选择bin、目录对应选项 5.激活 6.成功

MySQL--读写分离与分布式存储

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、读写分离 1、什么是读写分离 在数据库集群架构中&#xff0c;让主库负责处理写入操作&#xff0c;而从库只负责处理select查询&#xff0c;让两…

部署MySQL数据库时常见错误

登录数据库 时&#xff0c;可能会出现如图错误 1.确认是否部署MySQL服务 2.过滤MySQL端口号&#xff0c;查看服务是否开启&#xff08;如图上半部分&#xff0c;则是服务未开启&#xff09; 3.如图部分&#xff0c;则是密码错误 4.如果忘记了 mysql 的密码&#xff0c;或者登陆…

Apple Vision Pro 游戏开发:挑战与反思

随着Apple Vision Pro的推出,许多游戏开发者开始尝试在这个全新的平台上构建沉浸式的虚拟现实体验。然而,开发者们很快发现,在这个新兴领域中面临着不少挑战,包括支付延迟、技术支持不足、设备性能限制等问题。本文将探讨这些挑战,并提出一些开发者需要注意的关键点。 支…

Qt:自定义钟表组件

使用QWidget绘制两种钟表组件&#xff0c;效果如下&#xff1a; 源码下载链接&#xff1a;GitHub - DengYong1988/Clock-Widget: Qt 自定义钟表组件 https://download.csdn.net/download/ouyangxiaozi/89616407 主要代码如下&#xff1a; ClockWgt.h #ifndef CLOCKWGT_H #d…

spring源码阅读-推断构造方法

如何构造一个对象&#xff1f; 1、默认情况下&#xff0c;或者只有一个构造方法的情况下&#xff0c;就会使用默认构造方法或者唯一的一个构造方法 2、由程序员指定构造方法入参值&#xff0c;通过getBean()的方式获取&#xff0c;可以指定参数类型以及个数&#xff0c;但是该…

【康复学习--LeetCode每日一题】572. 另一棵树的子树

题目&#xff1a; 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree …

SpringBoot3里的文件上传

需求分析&#xff1a; 在用户更换头像或者添加文章时&#xff0c;都需要携带一个图片的URL访问地址。当用户访问文件上传接口将图片的数据上传成功后&#xff0c;服务器会返回一个地址。我们后台需要提供一个文件上传的接口&#xff0c;用来接收前端提交的文件的数据并且返回文…

C++入门基础(完整版)含下卷

C入门基础 hello 各位未来的程序员大佬们&#xff0c;这一篇是详细介绍入门基础&#xff0c;和上一篇不同的是这一篇补完了引用的知识和inline&#xff0c;nullptr的知识&#xff0c;希望大家有所收获 namespace的价值 在C/C中&#xff0c;变量、函数和后⾯要学到的类都是⼤…

【w门大学】云计算与大数据零基础特训班视频教程合辑

提取地址 云计算与大数据零基础特训班 课程目录

“数据要素×”大赛江西分赛官网正式上线 共设置12个赛道

7月17日&#xff0c;2024年“数据要素”大赛江西分赛在南昌市拉开帷幕。作为全国“数据要素”大赛的地方分赛&#xff0c;江西分赛由国家数据局、江西省人民政府指导&#xff0c;江西省发展改革委&#xff08;省数据局&#xff09;联合18家省级单位共同主办&#xff0c;江西分赛…

CCRC-DSA数据安全评估师:ISC.AI2024数字安全峰会:安全大模型引领安全行业革命

7月31日&#xff0c;以“构建先进的安全模型&#xff0c;引领安全产业变革”为主题&#xff0c;ISC.AI 2024数字安全峰会在北京国家会议中心成功举办。 本次峰会旨在鼓励行业通过大规模模型重构安全框架&#xff0c;确保数字经济的稳健前进。 会上&#xff0c;众多院士级专家…

【pytorch】全连接网络简单二次函数拟合

下面是一个使用PyTorch实现全连接网络来拟合简单二次函数 y x 2 y x^2 yx2 的示例。我们将创建一个简单的神经网络&#xff0c;定义损失函数和优化器&#xff0c;并进行训练。 下面是完整的代码示例&#xff1a; import torch import torch.nn as nn import torch.optim …

Linux笔记(1)

在敲出 文件 &#xff0f; 目录 &#xff0f; 命令 的前几个字母之后&#xff0c;按下 tab 键 如果输入的没有歧义&#xff0c;系统会自动补全 如果还存在其他 文件 &#xff0f; 目录 &#xff0f; 命令 &#xff0c;再按一下 tab 键&#xff0c;系统会提示可能存在的命令 小…

【算法速刷(5/100)】LeetCode —— 20.有效的括号

题目要求比较明晰简洁&#xff0c;编码难度并不算高 下面贴出代码和思路 bool isValid(string s) {stack<char> stk;for(const char& c : s){if(stk.empty()){stk.push(c);continue;}if(c ( || c [ || c {){stk.push(c);continue;}else{char top stk.top();boo…

Java Lambda表达式总结(快速上手图解)

Java Lambda表达式总结&#xff08;快速上手详解&#xff09;-CSDN博客https://blog.csdn.net/m0_66070037/article/details/140912566?spm1001.2014.3001.5501

idea 设置自动移除多余 的import (或整个项目删除)

1、开发的时候&#xff0c;直接自动去除多余的引入 2、如果想把整个项目的移除可以如下操作

Linux 异常 sh: /usr/bin/xauth: not found

异常原因&#xff1a; 远程连接时出现错误&#xff0c;由于 Omega 上没有 X 环境&#xff0c;因此在尝试交换凭据以设置转发时会失败 解决办法&#xff1a; 进入高级 SHH 设置&#xff0c;并勾选了 X11 转发。取消勾选该框。

Studying-代码随想录训练营day59| dijkstra(堆优化版)精讲、Bellman_ford 算法精讲

第59天&#xff0c;dijkstra算法的优化版本&#xff0c;以及Bellman_ford 算法&#x1f4aa;&#x1f4aa;(ง •_•)ง&#xff0c;编程语言&#xff1a;C 目录 dijkstra&#xff08;堆优化版&#xff09;精讲 思路 图的存储 邻接矩阵 邻接表 本题图的存储 堆优化细节…