Spring Boot整合Redis

GitHub:SpringBootDemo
Gitee:SpringBootDemo
微信公众号:在这里插入图片描述

0 开发环境

  • JDK:1.8
  • Spring Boot:2.7.18

1 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2 配置连接

spring:
  redis:
    host: 127.0.0.1
    port: 6379

代码中默认host是localhost,默认port是6379

3 测试

3.1 新建启动类

@SpringBootApplication
public class RedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
}

3.2 新建测试类

@SpringBootTest(classes = RedisApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class RedisApplicationTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void contextLoads() {
        redisTemplate.opsForValue().set("test_key", "test_value");
        System.out.println(redisTemplate.opsForValue().get("test_key"));
    }
}

3.3 测试

启动测试类,成功保存并取出打印

在这里插入图片描述

启动Redis客户端,查看数据,保存成功。

这里数据有乱码,是因为默认的序列化方式是JDK序列化,后面我们可以使用Json来序列化解决该问题。

在这里插入图片描述

4 对象序列化

在开发中,所有的对象存储到Redis中都需序列化

4.1 新建UserModel

/**
 * 未序列化,错误示范
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserModel {

    private int id;
    private String name;
}

4.2 调整测试类

    @Test
    public void contextLoadsUser() {
        UserModel user = new UserModel(1, "测试姓名");
        redisTemplate.opsForValue().set("test_user", user);
        System.out.println(redisTemplate.opsForValue().get("test_user"));
    }

4.3 测试

启动测试类,程序报错

在这里插入图片描述

4.4 调整UserModel

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserModel implements Serializable {

    private int id;
    private String name;
}

4.5 测试

再次启动测试类,数据成功保存并取出打印

在这里插入图片描述

这样,我们就能保存字符串和Java对象了。

然后针对前面所说的数据乱码问题,我们可以自定义RedisTemplate

5 自定义RedisTemplate

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        //JSON序列化配置
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //String序列化配置
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();

        //开启事务
        template.setEnableTransactionSupport(true);

        return template;
    }
}

6 测试

6.1 调整测试类

@SpringBootTest(classes = RedisApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class RedisApplicationTest {

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Test
    public void contextLoads() {
        redisTemplate.opsForValue().set("test_key", "test_value");
        System.out.println(redisTemplate.opsForValue().get("test_key"));
    }
}

6.2 测试

Redis客户端中执行flushdb清空数据,再次执行刚才的测试类,客户端中查看数据,数据保存成功,且无乱码

在这里插入图片描述

但是在实际开发中,我们基本是不会使用原生的方法来存取数据的,形如redisTemplate.opsForValue().set()编写代码比较麻烦。

通常,我们会自定义工具类,后续操作数据都通过工具类来处理。

7 自定义工具类

@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 指定缓存失效时间
     *
     * @param key     键
     * @param timeout 时间(秒)
     * @return
     */
    public boolean expire(String key, long timeout) {
        try {
            if (timeout > 0) {
                redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 0 永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false 不存在
     */
    public boolean hasKey(String key) {
        if (StringUtils.isEmpty(key)) {
            return false;
        }

        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true 成功 false 失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 时间(秒) time要大于0,如果time小于等于0,将设置无限期
     * @return true 成功 false 失败
     */
    public boolean set(String key, Object value, long timeout) {
        try {
            if (timeout <= 0) {
                return set(key, value);
            }

            redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param keys 可以传一个值或多个
     */
    public void delete(String... keys) {
        if (keys == null || keys.length <= 0) {
            return;
        }

        if (keys.length == 1) {
            redisTemplate.delete(keys[0]);
        } else {
            redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(keys));
        }
    }

    /**
     * 递增
     *
     * @param key
     * @param delta
     * @return
     * @throws Exception
     */
    public long increment(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须 > 0");
        }

        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key
     * @param delta
     * @return
     * @throws Exception
     */
    public long decrement(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须 > 0");
        }

        return redisTemplate.opsForValue().increment(key, -delta);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key     键 不能为null
     * @param hashKey 项 不能为null
     * @return true 存在 false 不存在
     */
    public boolean hasKeyHash(String key, String hashKey) {
        return Boolean.TRUE.equals(redisTemplate.opsForHash().hasKey(key, hashKey));
    }

    /**
     * 获取缓存
     *
     * @param key     键 不能为null
     * @param hashKey 项 不能为null
     * @return 值
     */
    public Object getHash(String key, String hashKey) {
        return key == null ? null : redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key     键
     * @param hashKey 项
     * @param value   值
     * @return true 成功 false失败
     */
    public boolean setHash(String key, String hashKey, Object value) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key     键
     * @param hashKey 项
     * @param value   值
     * @param timeout 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false 失败
     */
    public boolean setHash(String key, String hashKey, Object value, long timeout) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);

            if (timeout > 0) {
                expire(key, timeout);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key      键 不能为null
     * @param hashKeys 项 可以是多个 不能为null
     */
    public void deleteHash(String key, Object... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 递增
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public long incrementHash(String key, String hashKey, long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * 递增
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public double incrementHash(String key, String hashKey, double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * 递减
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public long decrementHash(String key, String hashKey, long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    /**
     * 递减
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public double decrementHash(String key, String hashKey, double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    /**
     * 获取key对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> getHash(String key) {
        return key == null ? null : redisTemplate.opsForHash().entries(key);
    }

    /**
     * 缓存
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean setHash(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 缓存并设置超时时间
     *
     * @param key     键
     * @param map     对应多个键值
     * @param timeout 时间(秒)
     * @return true 成功 false 失败
     */
    public boolean setHash(String key, Map<String, Object> map, long timeout) {
        try {
            redisTemplate.opsForHash().putAll(key, map);

            if (timeout > 0) {
                expire(key, timeout);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> membersSet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false 不存在
     */
    public boolean isMemberSet(String key, Object value) {
        try {
            return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long addSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key     键
     * @param timeout 时间(秒)
     * @param values  值 可以是多个
     * @return 成功个数
     */
    public long addSet(String key, long timeout, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (timeout > 0) {
                expire(key, timeout);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sizeSet(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long removeSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束  0到-1代表所有值
     * @return
     */
    public List<Object> rangeList(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sizeList(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引获取list中的值
     *
     * @param key   键
     * @param index 索引  index>=0时,0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object indexList(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean rightPushList(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key     键
     * @param value   值
     * @param timeout 时间(秒)
     * @return
     */
    public boolean rightPushList(String key, Object value, long timeout) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (timeout > 0) {
                expire(key, timeout);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean rightPushList(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key     键
     * @param value   值
     * @param timeout 时间(秒)
     * @return
     */
    public boolean rightPushList(String key, List<Object> value, long timeout) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (timeout > 0) {
                expire(key, timeout);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean setList(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value的数据
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long removeList(String key, long count, Object value) {
        try {
            return redisTemplate.opsForList().remove(key, count, value);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

8 测试

8.1 调整测试类

@SpringBootTest(classes = RedisApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class RedisApplicationTest {

    @Autowired
    private RedisUtils redisUtils;

    @Test
    public void contextLoadsUtil() {
        redisUtils.set("test_utils_key", "test_utils_value");
        System.out.println(redisUtils.get("test_utils_key"));
    }
}

8.2 测试

启动测试类,成功保存并取出打印

在这里插入图片描述

至此,Spring Boot整合Redis完成且测试通过,可以看到,对于Redis的相关操作还是比较简单的,关键在于理解Redis的思想和每一种数据结构的用法和作用场景。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Anaconda和Python是什么关系?

Anaconda和Python相当于是汽车和发动机的关系&#xff0c;你安装Anaconda后&#xff0c;就像买了一台车&#xff0c;无需你自己安装发动机和其他零配件&#xff0c;而Python作为发动机提供Anaconda工作所需的内核。 简单来说&#xff0c;Anaconda是一个集成了IDE、Notepad、P…

IDEA使用常用的设置

一、IDEA常用设置 可参考&#xff1a;IDEA这样配置太香了_哔哩哔哩_bilibili 波波老师 二、插件 可参考&#xff1a;IDEA好用插件&#xff0c;强烈推荐_哔哩哔哩_bilibili 波波老师 三、其他 学会用点“.” IDEA弹窗Servers certificate is not trusted怎么禁止&#xf…

在项目中缓存如何优化?SpringCache接口返回值的缓存【CachePut、CacheEvict、Cacheable】

SpringCache 介绍&#xff08;不同的缓存技术有不同的CacheManager&#xff09;注解入门程序环境准备数据库准备环境准备注入CacheManager引导类上加EnableCaching CachePut注解(缓存方法返回值)1). 在save方法上加注解CachePut2). 测试 CacheEvict注解&#xff08;清理指定缓存…

canal: 连接kafka (docker)

一、确保mysql binlog开启并使用ROW作为日志格式 docker 启动mysql 5.7配置文件 my.cnf [mysqld] log-binmysql-bin # 开启 binlog binlog-formatROW # 选择 ROW 模式 server-id1一定要确保上述两个值一个为ROW&#xff0c;一个为ON 二、下载canal的run.sh https://github.c…

[串讲]MySQL 存储原理 B+树

InnoDB 是一种兼顾高可靠性和高性能的通用存储引擎&#xff0c;在 MySQL 5.5 之后&#xff0c;InnoDB 是默认的 MySQL 存储引擎。 InnoDB 对每张表在磁盘中的存储以 xxx.ibd 后缀结尾&#xff0c;innoDB 引擎的每张表都会对应这样一个表空间文件&#xff0c;用来存储该表的表结…

全局自定义指令实现图片懒加载,vue2通过js和vueuse的useintersectionObserver实现

整体逻辑&#xff1a; 1.使用全局自定义指令创建图片懒加载指令 2.在全局自定义指令中获取图片距离顶部的高度和整个视口的高度 3.实现判断图片是否在视口内的逻辑 一、使用原生js在vue2中实现图片懒加载 1.创建dom元素,v-lazy为自定义指令&#xff0c;在自定义指令传入图片…

python使用pygame做第一个孩子游戏

作者&#xff1a;ISDF 功能&#xff1a;孩子游戏 版本&#xff1a;3.0 日期&#xff1a;03/29/2019作者&#xff1a;ISDF 功能&#xff1a;孩子游戏 版本&#xff1a;4.0 日期&#xff1a;03/27/2024 import pygame from pygame.locals import * import sys from itertools imp…

Python7:接口自动化学习1 RPC

API&#xff08;Application Programmming Interface&#xff09; 应用编程接口&#xff0c;简称“接口” 接口&#xff1a;程序之间约定的通信方法 特点&#xff1a;约定了调用方法&#xff0c;以及预期的行为&#xff0c;但是不透露具体细节 意义&#xff1a;程序能解耦&…

FPGA高端项目:解码索尼IMX390 MIPI相机转HDMI输出,提供FPGA开发板+2套工程源码+技术支持

目录 1、前言2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX390 及其配置MIPI CSI RX图像 ISP 处理图像缓存HDMI输出工程源码架构 6、工程源码…

Trapcode Particular---打造惊艳粒子效果

Trapcode Particular是Adobe After Effects中的一款强大3D粒子系统插件&#xff0c;其能够创造出丰富多样的自然特效&#xff0c;如烟雾、火焰和闪光&#xff0c;以及有机的和高科技风格的图形效果。Trapcode Particular功能丰富且特色鲜明&#xff0c;是一款为Adobe After Eff…

视觉里程计之对极几何

视觉里程计之对极几何 前言 上一个章节介绍了视觉里程计关于特征点的一些内容&#xff0c;相信大家对视觉里程计关于特征的描述已经有了一定的认识。本章节给大家介绍视觉里程计另外一个概念&#xff0c;对极几何。 对极几何 对极几何是立体视觉中的几何关系&#xff0c;描…

新能源汽车充电桩主板各模块成本占比解析

汽车充电桩主板是汽车充电桩的重要组件&#xff0c;主要由微处理器模块、通信模块、控制模块、安全保护模块、传感器模块等多个模块构成。深入探究各模块在总成本中的比重&#xff0c;我们可以更好地优化成本结构、提高生产效率&#xff0c;并为未来的技术创新和市场需求变化做…

网络层介绍,IP地址分类以及作用

IP地址组成&#xff1a; TTL&#xff1a;生存时间 基于ICMP报文 特殊地址&#xff1a; 0.0.0.0-0.255.255.255 1.代表未指定的地址 默认路由 DHCP下发地址的时候&#xff0c;发个报文给DHCP服务器 临时用0.0.0.0借用地址&#xff0c;未指定地址。 2.全网地址&#xff1a;目…

iNet Network Scanner Mac 网络扫描工具

iNet Network Scanner for Mac是一款功能强大的网络扫描工具&#xff0c;专为Mac用户设计。它提供了全面而深入的网络分析功能&#xff0c;使用户能够轻松获取Mac连接的网络和设备的详细信息。 软件下载&#xff1a;iNet Network Scanner Mac v3.1.0激活版 这款软件具备多种扫描…

自动驾驶-如何进行多传感器的融合

自动驾驶-如何进行多传感器的融合 附赠自动驾驶学习资料和量产经验&#xff1a;链接 引言 自动驾驶中主要使用的感知传感器是摄像头和激光雷达&#xff0c;这两种模态的数据都可以进行目标检测和语义分割并用于自动驾驶中&#xff0c;但是如果只使用单一的传感器进行上述工作…

使用Spark单机版环境

在Spark单机版环境中&#xff0c;可通过多种方式进行实战操作。首先&#xff0c;可使用特定算法或数学软件计算圆周率π&#xff0c;并通过SparkPi工具验证结果。其次&#xff0c;在交互式Scala版或Python版Spark Shell中&#xff0c;可以进行简单的计算、打印九九表等操作&…

Gerber文件输出

Gerber文件输出 综述&#xff1a;本文主要讲述了AD软件中相关文件的导出&#xff08;装配图、BOM表、Gerber文件&#xff09;及文件的整理。 1. 输出装配图 方法一&#xff1a;点击“文件”→“装配输出”→“Assembly Drawings”&#xff0c;即可输出装配图&#xff0c;但是…

代码随想录 图论-并查集

代码随想录 (programmercarl.com) 寻找图中是否存在路径这道题中的类可看做并查集的标准类 目录 1971.寻找图中是否存在路径 684.冗余连接 685.冗余连接II 1971.寻找图中是否存在路径 1971. 寻找图中是否存在路径 已解答 简单 相关标签 相关企业 有一个具有 n 个顶…

文心一言指令词宝典之职场效率篇

作者&#xff1a;哈哥撩编程&#xff08;视频号、抖音、公众号同名&#xff09; 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏&#xff1a; &#x1f3c5;…

OriginBot智能机器人开源套件

详情可参见&#xff1a;OriginBot智能机器人开源套件——支持ROS2/TogetherROS&#xff0c;算力强劲&#xff0c;配套古月居定制课程 (guyuehome.com) OriginBot智能机器人开源套件 最新消息&#xff1a;OriginBot V2.1.0版本正式发布&#xff0c;新增车牌识别&#xff0c;点击…