Redis-基础篇

news2024/11/18 3:23:10

Redis是一个开源、高性能、内存键值存储数据库,由 Salvatore Sanfilippo(网名antirez)创建,并在BSD许可下发布。它不仅可以用作缓存系统来加速数据访问,还可以作为持久化的主数据存储系统或消息中间件使用。Redis因其数据结构丰富、性能优异和高可用性而被广泛应用在现代分布式架构中。

目录

一、认识Redis

1.1、认识NoSQL

1.2、认识Redis

1.3、安装Redis

二、Redis的常见命令

2.1、5种常见的数据结构

2.2、通用命令

2.3、不同数据结构的操作命令

三、Redis的Java客户端

3.1、Jedis客户端

3.2、SpringDataRedis客户端


一、认识Redis

1.1、认识NoSQL

SQL:结构化、表有关联、支持SQL查询、满足事务的ACID、存储在磁盘、垂直扩展、适用于数据结构固定,相关业务的数据安全性与一致性要求高的场合

NoSQL:非结构、无关联的、非SQL、满足基本一致性、存储在内存、水平扩展、适用于数据结构不固定,对一致性与安全性要求不高,但是对性能要求较高的场合

常见的NoSQL有:键值对类型的Redis、文档类型的MongoDB

1.2、认识Redis

Redis( Remote Dictionary Server)的全程是远程字典服务器,是一个基于内存的非关系型数据库。

redis的特征:
1.键值对类型的数据库,支持丰富的数据类型

2.单线程,每个命令具备原子性

3.低延迟,速度快(基于内存、IO多路复用、良好的编码)

4.支持数据的持久化

5.支持主从集群与分片集群

6.支持多语言客户端

1.3、安装Redis

这个不过多介绍,直接下载安装即可。

安装redis服务器和客户端,并安装redis可视化管理工具Another Redis Desktop Manager。

二、Redis的常见命令

2.1、5种常见的数据结构

redis是一个键值对类型的数据库,key的类型一般是String,value的类型就多种多样:

基本数据类型:

String类型:缓存用户信息、计数器(例如点赞数、浏览量)、简单的键值对存储等。

Hash类型:存储用户属性集合(如用户的姓名、年龄、地址等)、产品详情等多字段数据结构。

List类型:存储用户属性集合(如用户的姓名、年龄、地址等)、产品详情等多字段数据结构。

Set类型:适用于标签系统(给一篇文章打上多个标签)、唯一事件记录等。

SortedSet类型:跳跃表提供O(log N)级别的插入、删除和查找操作,并按分数排序。

特殊数据类型:

GEO类型:Geo数据类型允许用户存储地理位置信息,并执行地理半径查询、邻近点搜索等操作。

BitMap类型:用于用户在线状态跟踪、访问统计(例如用户是否读过某篇文章)。

HyperLog类型:日活用户统计、网站独立访客统计、广告点击去重等需要估算大量唯一元素数量而不需精确存储所有元素的场景。

2.2、通用命令

通用命令常见的有:

KEYS:查看符合模板的所有key,不建议在生产环境上使用

DEL:删除一个指定的key

EXISTS:判断一个key是否存在

EXPIRE:为一个key设置有效期,有效期到了key会自动删除

TTL:查看key的剩余有效期

2.3、不同数据结构的操作命令

String类型:字符串类型,包括普通字符串,整数,浮点数

API如下:

SET:添加或者修改string类型的键值对

GET:根据key获取string类型的value

MSET:批量添加多个string类型的键值对

MGET:根据string类型的key获取多个string类型的值

INCR:让整型的key自增1

INCREBY:整数设置步长的自增

INCREBYFLOAT:按照指定步长的浮点型自增

SETNX:添加一个string类型的键值对,前提是key不存在,否则不执行

SETEX:添加一个string类型的键值对,并指定有效期

redis的key允许有多个单词形成层级结构,多个单词用“:”隔开,如果value是一个Java对象,则可以将对象序列化成JSON字符串后存储:
例如key可以为  项目名:业务名:类型:id      value为{“id”:1,"product":"小米手机","price":"2999"}

这样redis会根据冒号:进行层级划分。

Hash类型:也称为散列,value是一个无序字典,类似于Java中的HashMap结构。之前的string类型的value是将对象序列化成JSON字符串后存储,当需要修改某个字段时很不方便。

Hash结构可以将每个字段独立存储,可以针对每个字段进行操作。

相关的API:

HSET key field value:添加或者修改hash类型的key的field值

HGET key field:获取一个hash类型的key的field值

HMSET:批量添加多个hash类型key的field值

HMGET:批量查询多个hash类型key的field值

HGETALL:获取一个hash类型key的所有feild的值

HKEYS:获取一个hash类型的key中的所有feild

HVALS:获取一个hash类型的key中的所有value

HINCREBY:让hash类型的key自增并指定步长

HSETNX:添加一个hash类型的field,前提是field不存在,否则不执行

List类型:List类型与Java中的LinkedList类似,可以看作是一个双向链表,支持正向与反向检索。

特征:有序、允许元素重复、插入删除快、查询速度一般

List的常见命令如下:

LPUSH key element...:向列表左侧插入一个或者多个元素

LPOP key :移除并返回列表左侧额第一个元素,没有则返回nil

RPUSH key element...:向列表右侧插入一个或者多个元素

RPOP key:移除并返回列表右侧的第一个元素

LRANGE key  start end:返回一段角标范围内的所有元素

BLPOP与BRPOP:移除指定的元素,没有元素时并设置等待时间,而不是直接返回nil

List模拟栈:lpush与lpop  rpush与rpop

List模拟队列:lpush与rpop

List模拟阻塞队列:blpop与brpop

Set类型:Redis中的set与Java中的HashSet类似,具有如下特征:无序、元素不可重复、查找快

、支持交集、并集差集等操作。

SET类型的常见命令:

SADD key member...:向set中添加一个或者多个元素

SREM key member...:向set中移除指定元素

SCARD key:返回set中的元素个数

SISMEMBER key member:判断一个元素是否在set中

SMEMBERS:获取set中的所有元素

SINTER key1 key2:求两个key的交集

SDIFF:求两个集合的差集

SUNION:求两个集合的并集

SortedSet类型:有序的集合,每个元素都带有一个score属性,可以根据score属性进行排序,底层是一个跳表+hash表的实现。跳跃表提供O(log N)级别的插入、删除和查找操作,并按分数排序;hash表用于快速查找成员的存在性。

跳表是通过随机函数维护平衡性的,当我们在跳表中插入数据的时候,我们通过选择同时将这个数据插入到部分索引层中,如何选择索引层,可以通过一个随机函数来决定这个节点插入到哪几级索引中,比如随机生成了k,那么就将这个索引加入到,第一级到第k级索引中。

SortedSet具有以下特点:

1、可排序 2、元素不重复 3、查询速度快

常见的SortedSort的api如下:默认是升序,如果向降序前缀由Z改成ZREV

三、Redis的Java客户端

3.1、Jedis客户端

常见的Redis的Java客户端有Jedis、Lettuce、Redisson三种,具体如下。

下面我们通过jedis客户端连接redis服务器,并进行单元测试,具体如下:

1.首先添加三方依赖。

    <!--jedis客户端依赖-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.7.0</version>
        </dependency>

        <!-- junit测试依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>

2.编写单元测试模块,jedis客户端连接redis服务器,并进行crud基本操作,最后释放连接。

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

/**
 * @author nuist__NJUPT
 * @ClassName JedisTest
 * @description: jedis测试类
 * @date 2024/03/02
 */
public class JedisTest {

    private Jedis jedis ;

    @BeforeEach
    void setUp(){
        // 1.建立连接
        jedis = new Jedis("localhost", 6379) ;
        // 2.设置密码
        jedis.auth("123456") ;
        // 3.选择库
        jedis.select(0) ;
    }

    @Test
    void testString(){

        // 存入数据
        String result = jedis.set("name", "mandy");
        System.out.println(result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name : " + name );

    }

    @Test
    void testHash(){
        // 存值
        jedis.hset("user:1", "name", "jack") ;
        jedis.hset("user:1", "age", "21") ;
        // 取值
        Map<String, String> stringStringMap = jedis.hgetAll("user:1");
        System.out.println(stringStringMap);

    }

    @AfterEach
    void tearDown(){
        if(jedis != null){
            jedis.close();
        }
    }

}

jedis本身是线程不安全的,而且频繁的创建与销毁jedis连接会有性能损耗,因此推荐使用jedis连接池的方式代替直连的方式。

1.定义一个连接池工具类,用于建立jedis连接,并返回jedis对象,jedis使用完放回连接池而不是直接销毁。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author nuist__NJUPT
 * @ClassName JedisConnectionFactory
 * @description: Jedis连接池
 * @date 2024/03/02
 */
public class JedisConnectionFactory {

    private static final JedisPool jedisPool ;

    static {
        // 配置连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(8);
        jedisPoolConfig.setMaxIdle(8);
        jedisPoolConfig.setMinIdle(0);
        jedisPoolConfig.setMaxWaitMillis(1000);

        // 创建连接池对象
        jedisPool= new JedisPool(jedisPoolConfig, "localhost", 6379, 1000, "123456");
    }

    public static Jedis getJedis(){
        return jedisPool.getResource() ;
    }

}

2.客户端直接通过连接池获取jedis对象就可以,不用直接newjedis对象进行直连了。

import com.alibaba.jedis.util.JedisConnectionFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

/**
 * @author nuist__NJUPT
 * @ClassName JedisTest
 * @description: jedis测试类
 * @date 2024/03/02
 */
public class JedisTest {

    private Jedis jedis ;

    @BeforeEach
    void setUp(){
        // 1.建立连接
        // jedis = new Jedis("localhost", 6379) ;
        jedis = JedisConnectionFactory.getJedis() ;
        // 2.设置密码
        jedis.auth("123456") ;
        // 3.选择库
        jedis.select(0) ;
    }

    @Test
    void testString(){

        // 存入数据
        String result = jedis.set("name", "mandy");
        System.out.println(result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name : " + name );

    }

    @Test
    void testHash(){
        // 存值
        jedis.hset("user:1", "name", "jack") ;
        jedis.hset("user:1", "age", "21") ;
        // 取值
        Map<String, String> stringStringMap = jedis.hgetAll("user:1");
        System.out.println(stringStringMap);

    }

    @AfterEach
    void tearDown(){
        if(jedis != null){
            jedis.close();
        }
    }

}

3.2、SpringDataRedis客户端

SpringData是Spring中数据操作的模块,包含了对多种数据库的集成,其中对redis的集成就是SpringDataRedis。它提供了对不同redis客户端的整合(jedis、Lettuce),提供了RedisTemplate统一API来操作Redis,支持redis的发布订阅模型,支持redis哨兵和redis集群,支持基于Lettuce的响应式编程,支持序列化与反序列化。

下面看一下SpringDataRedis提供的工具类RedisTemplate的应用,首先创建springboot项目并导入redis依赖。

  <!--	jackson依赖	-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.5</version>
        </dependency>

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

        <!-- 连接池依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

然后在yml文件中进行配值,配值redis的数据源信息。

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100

编写redisTemplate的配值类,防止在redis在接收Object类型时,把Object对象序列化成字节形式,变成一串乱码,可读性差,占用内存。


/**
 * @author nuist__NJUPT
 * @ClassName RedisConfig
 * @description: redis配置类
 * @date 2024/03/02
 */


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig {

    /**
     * RedisTemplate可以接收任意Object作为值写入Redis,
     * 只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的一串很长的值
     * 缺点:可读性查、浪费存储空间
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 1.创建 redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 2.设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 3.设置序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // key 采用 String 序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // value 采用 json 序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);

        return  redisTemplate;

    }
}

定义一个实体类。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author nuist__NJUPT
 * @ClassName User
 * @description: 实体类
 * @date 2024/03/02
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private String name ;
    private Integer age ;

}

最后编写单元测试模块,利用redisTemplate进行测试。

import com.alibaba.redisdemo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class RedisDemoApplicationTests {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Test
    void testString(){

        // 添加一个元素
        redisTemplate.opsForValue().set("name", "Jack");
        // 获取元素
        Object object = redisTemplate.opsForValue().get("name");
        System.out.println(object);
    }

    @Test
    void testSaveUser(){
        //写入数据
        redisTemplate.opsForValue().set("user:2", new User("wang", 18));
        // 读取数据
        User user = (User) redisTemplate.opsForValue().get("user:2");
        System.out.println(user);
    }
  @Test
    void testHash(){

        stringRedisTemplate.opsForHash().put("user:3","name", "liu");
        stringRedisTemplate.opsForHash().put("user:3","age","18") ;

        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:3");
        System.out.println("entries = " + entries);

    }

}

上述尽管Json序列化的方式满足要求,但是会发现仍然存在一些问题,比如JSON序列化器将类型class写入了json中,存入redis会导致额外的内存开销。

为了节省内存空间,不使用JSON序列化来处理value,而是处理String序列化器,要求只能存储String类型的key与value,当存储Java对象的时候需要手动的序列化与反序列化。

可以采用如下写法:
 

 @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    private static final ObjectMapper mapper = new ObjectMapper() ;
    @Test
    void testSave() throws JsonProcessingException {
        // 创建对象
        User user = new User("wang", 18);
        // 手动序列化
        String s = mapper.writeValueAsString(user);
        //写入数据
        stringRedisTemplate.opsForValue().set("user:2",s);
        // 读取数据
        String user1 = stringRedisTemplate.opsForValue().get("user:2");
        // s手动反序列化
        User user2 = mapper.readValue(user1, User.class);

        System.out.println(user2);
    }

使用fastJson进行序列化与反序列化也可以,需要添加依赖。

    @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    @Test
    void testSave() throws JsonProcessingException {
        // 创建对象
        User user = new User("wang", 19);
        // 手动序列化
        String s = JSON.toJSONString(user) ;
        //写入数据
        stringRedisTemplate.opsForValue().set("user:2",s);
        // 读取数据
        String user1 = stringRedisTemplate.opsForValue().get("user:2");
        // s手动反序列化
        User user2 = JSON.parseObject(user1, User.class) ;

        System.out.println(user2);
    }

添加fastJson依赖。

<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.32</version>
</dependency>

总结:redis中有两种序列化方式,推荐使用第二种。

1.第一种是自定义RedisTemplate,修改其序列化器,相对方便,但是写入redis会存class对象,占用额外的内存空间。

2.使用StringRedisTemplate,默认使用String序列化器,写入redis需要将Java对象手动序列化为json,读取redis需要将读取到的json反序列化为Java对象。

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

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

相关文章

从下一代车规MCU厘清存储器的发展(2)

目录 1.概述 2.MCU大厂的选择 2.1 瑞萨自研STT-MRAM 2.2 ST专注PCM 2.3 英飞凌和台积电联手RRAM 2.4 NXP如何计划eNVM 3.小结 1.概述 上篇文章&#xff0c;我们简述了当前主流的存储器技术&#xff0c;现在我们来讲讲各大MCU大厂的技术选择 2.MCU大厂的选择 瑞萨日…

vue2结合electron开发桌面端应用

一、Electron是什么&#xff1f; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 。允许您保持一个 JavaScript 代码代码库并创建可在Windows、macOS和Linux上运行的跨平台应用 。 Electron 经常与 Ch…

文献阅读笔记《Spatial-temporal Forecasting for Regions without Observations》13页

目录 目录 目录 发行刊物 ABSTRACT 1 INTRODUCTION 2 RELATED WORK&#xff08;相关工作 2.1 Spatial-temporal Forecasting&#xff08;时空预测 2.2 Spatial-temporal Forecasting withIncomplete Data&#xff08;不完全数据的时空预测 2.3 Graph Contrastive Lear…

什么是Vue指令?请列举一些常见的Vue指令以及它们的用法

Vue.js 是一款流行的前端框架&#xff0c;它的指令&#xff08;Directives&#xff09;是 Vue.js 提供的一种特殊属性&#xff0c;用于在模板中对 DOM 元素进行直接操作。指令通常是以 v- 开头的特殊属性&#xff0c;用于响应式地将数据绑定到 DOM 元素上。 在 Vue 中&#xf…

VS Code(Visual Studio Code)本地(local)和远程(ssh)Docker Container 下的 Python 开发和调试

VS Code&#xff08;Visual Studio Code&#xff09;本地&#xff08;local&#xff09;和远程&#xff08;ssh&#xff09;Docker Container 下的 Python 开发和调试 1. 目的需求2. VS Code 简介3. 使用实践&#xff1a;一个简单的实例3.1 准备工作3.1.1 远程服务器3.1.2 本地…

测试面试精选题:可用性测试主要测试哪些方面,举例说明

1.界面设计&#xff1a; 评估软件的用户界面设计是否直观、美观、易于理解和操作。 测试用例&#xff1a;打开软件&#xff0c;查看界面布局是否合理&#xff0c;各个功能是否容易找到&#xff0c;是否符合用户习惯。 2.导航和布局&#xff1a; 评估用户在软件中导航和查找…

点云数据结构化与体素化理论学习

一、PCD点云数据存储格式的进一步认识 &#xff08;一&#xff09;PCD点云存储格式相较于其它存储格式&#xff08;如PLY、STL、OBJ、X3D等&#xff09;的优势[1] &#xff08;1&#xff09;具有存储和处理有组织的点云数据集的能力&#xff0c;这对于实时应用和增强现实及机器…

【C++】string 类 ( 上)

标准库中的string类 注意&#xff1a; 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同&#xff0c;再添加了一些专门用来操作string的常规操作。 比特就业课 3. string在底层实际是&#xff1a;basic_string模板类的别名&#xff0c;typedef basi…

Python3零基础教程之数学运算专题初阶

大家好,我是千与编程,在上一节课程我们讲解了Python3基础课程中的变量与数据专题项目,本章节中涉及的Python3编程语言中的基础的四则运算、赋值运算符号,赋值运算符号,比较运算符号,位运算符号的计算方法。 这一章的内容算是比较基础的部分,最后需要学会使用即可。以下是…

飞天使-学以致用-devops知识点2-安装sonarqube

文章目录 安装sonarqube查看暴露出去的端口 生成服务token创建webhook服务创建项目 安装sonarqube apiVersion: apps/v1 kind: Deployment metadata:name: postgres-sonarnamespace: kube-devops spec:replicas: 1selector:matchLabels:app: postgres-sonartemplate:metadata:…

物联网与智慧城市:科技驱动下的城市智能化升级之路

一、引言 随着科技的不断进步和城市化进程的加速&#xff0c;物联网与智慧城市的结合已经成为推动城市智能化升级的关键力量。物联网技术以其强大的连接和数据处理能力&#xff0c;为智慧城市的建设提供了无限可能。本文旨在探讨物联网如何助力智慧城市的构建&#xff0c;以及…

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议&#xff08;主机与主机&#xff09;IP地址的分类…

朱维群将出席用碳不排碳碳中和顶层科技路线设计开发

演讲嘉宾&#xff1a;朱维群 演讲题目&#xff1a;“用碳不排碳”碳中和顶层科技路线设计开发 简介 姓名&#xff1a;朱维群 性别&#xff1a;男 出生日期&#xff1a;1961-09-09 职称&#xff1a;教授 1998年毕业于大连理工大学精细化工国家重点实验室精细化工专业&…

【ArcGIS Pro二次开发】(83):ProWindow和WPF的一些技巧

在ArcGIS Pro二次开发中&#xff0c;SDK提供了一种工具界面【ArcGIS Pro ProWindow】。 关于ProWindow的用法&#xff0c;之前写过一篇基础的教程&#xff1a; 【ArcGIS Pro二次开发】(13)&#xff1a;ProWindow的用法_arcgispro二次开发教程-CSDN博客 主要是对几个常用控件…

Codeforces Round 930 (Div. 2 ABCDEF题) 视频讲解

A. Shuffle Party Problem Statement You are given an array a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​. Initially, a i i a_ii ai​i for each 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n. The operation swap ( k ) \texttt{swap}(k) swap(k) for an…

Java练习(第5天)【总结】在字符串中寻找特定的字符(5种方法)

问题描述&#xff1a;在字符串中寻找特定字符 1、第1次出现位置 实现函数原型&#xff1a; int indexOf(char c) Java代码&#xff1a; import java.io.*; public class Way_1 {public static void main(String args[]){String str "Geeks for Geeks is a computer s…

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护)

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护) 边缘小站的主要功能是管理用户在线下部署的整机柜设施&#xff0c;一个边缘小站关联一个华为云指定的区域和一个用户指定的场地&#xff0c;相关的资源运行状况监控等。 边缘计算 迈入5G和AI时代&#xff0c;新…

【嵌入式实践】【芝麻】【设计篇-2】从0到1给电动车添加指纹锁:项目可行性分析

0. 前言 该项目是基于stm32F103和指纹模块做了一个通过指纹锁控制电动车的小工具。支持添加指纹、删除指纹&#xff0c;电动车进入P档等待时计时&#xff0c;计时超过5min则自动锁车&#xff0c;计时过程中按刹车可中断P档状态&#xff0c;同时中断锁车计时。改项目我称之为“芝…

Arcgis重分类

对于一张土地分类图&#xff0c;有时需要改变他的类型对应的值&#xff0c;如何在Arcgis中完成这个操作&#xff1f; 有时候&#xff0c;需要对土地利用类型的水土保持因子P进行赋值&#xff0c;林地、草地赋值给1&#xff0c;水田0.15&#xff0c;旱地0.35&#xff0c;水域、…

FreeRTOS学习笔记——FreeRTOS中断管理

什么是中断&#xff1f; 简介&#xff1a;让CPU打断正常运行的程序&#xff0c;转而去处理紧急的事件&#xff08;程序&#xff09;&#xff0c;就叫中断 例&#xff1a; 中断执行机制&#xff0c;可简单概括为三步&#xff1a; 中断优先级分组设置 ARM Cortex-M 使用了 8 位…