redis深入理解之实战

1、SpringBoot整合redis

1.1 导入相关依赖

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

1.2 创建Jedis对象,调用API

直接使用

@Test
public void redisTestDemo() throws InterruptedException{String host = "127.0.0.1";int port = 6379;Jedis jedis = new Jedis(host, port);jedis.set("name", "hua");System.out.println("执行setAPI后,redis中的name对应的值是:"+jedis.get("name"));jedis.setex("name",20,"32");System.out.println("执行setex后,redis中的name对应的值是:"+jedis.get("name"));Thread.sleep(1000);System.out.println("线程睡一会后检查name生存时间为:");System.out.println(jedis.persist("name"));Thread.sleep(1002);System.out.println("再次线程休眠检查name是否存在");System.out.println(jedis.exists("name"));jedis.flushAll();System.out.println("执行flushAllAPI后,检查name Key是否存在");System.out.println(jedis.exists("name"));
}

使用配置文件的方式实现

redisConfig.properties

jedis.host=127.0.0.1
jedis.port=6379
#jedis.password=yourpassword
#jedis.timeout=5000

RedisConfig配置类

@Configuration
@PropertySource("classpath:redisConfig.properties")
public class JedisConfig {@Value("${jedis.host}")private String jdsHost;@Value("${jedis.port}")private Integer jdsPort;@Bean("jds")public Jedis getJedis(){return new Jedis(jdsHost,jdsPort);}

测试类

@Autowired
@Qualifier("jds")
private Jedis jedis;@Test
public void redisTestDemo() throws InterruptedException{jedis.set("name", "hua");System.out.println("执行setAPI后,redis中的name对应的值是:"+jedis.get("name"));jedis.setex("name",20,"32");System.out.println("执行setex后,redis中的name对应的值是:"+jedis.get("name"));Thread.sleep(1000);System.out.println("线程睡一会后检查name生存时间为:");System.out.println(jedis.persist("name"));Thread.sleep(1002);System.out.println("再次线程休眠检查name是否存在");System.out.println(jedis.exists("name"));jedis.flushAll();System.out.println("执行flushAllAPI后,检查name Key是否存在");System.out.println(jedis.exists("name"));
}

结果

2、redis分片机制

2.1 redis分片机制概述

1.业务需要:

由于单台redis内存容量是有限的,无法实现海量的数据实现缓存存储。

2.分片机制概述:

概念:由多个redis节点协助工作的机制就是redis的分片机制。

作用:是为了实现redis扩容。

特点:分片机制把该机制中包含的多台redis缓存服务器当做一个整体,即看做一台redis服务器使用。

缺点:当redis分片中一个节点宕机,则可能会影响整个服务的运行,redis分片没有实现高可用。

2.2 分片机制的实现

①文件配置

1.配制规划:准备3台redis

方式:一台redis启动需要一个redis配置文件。因此实现三台redis,只需三个redis.conf文件即可。

2.修改配置文件:使3台redis的端口各不相同,如果相同则必定不能同时启动三台redis。

修改内容示例:

port 6379

port 7640

port 7639

3. 启动每个redis端口

进入redis安装目录

redis-server.exe redis.windows7640.conf
redis-server.exe redis.windows7639.conf
redis-server.exe redis.windows.conf

②SpringBoot项目使用redis分片机制

  1. 直接使用
//redis分片机制的实现
@Test
public void redisShards(){List<JedisShardInfo> shards = new ArrayList<>();shards.add(new JedisShardInfo("localhost",6379));shards.add(new JedisShardInfo("localhost",7639));shards.add(new JedisShardInfo("localhost",7640));ShardedJedis sjedis = new ShardedJedis(shards);sjedis.setnx("z7", "redis分片操作7");sjedis.setnx("z8", "redis分片操作8");sjedis.setnx("z9", "redis分片操作9");System.out.println("z7:"+sjedis.get("z7"));System.out.println("z8:"+sjedis.get("z8"));System.out.println("z9:"+sjedis.get("z9"));
}
  1. 配置文件方式实现

redisConfig.properties配置文件

#配置redis分片中各节点信息
jedis.info=127.0.0.1:6379,127.0.0.1:7639,127.0.0.1:7640

RedisConfig配置类

@Value("${jedis.info}")
private String jdsInfo;@Bean
public ShardedJedis shardedJedis(){//第一步,获取分片机制整合的每台redis的信息,并封装成一个JedisSharedInfo对象List<JedisShardInfo> shards = new ArrayList<>();String[] jedisInfo = jdsInfo.split(",");for(String s: jedisInfo){String[] allSubStr = s.split(":");shards.add(new JedisShardInfo(allSubStr[0], Integer.parseInt(allSubStr[1])));}return new ShardedJedis(shards);
}

测试类

@Autowired
private ShardedJedis sjedis;//redis分片机制的实现@Testpublic void redisShards(){sjedis.setnx("z7", "redis分片操作7");sjedis.setnx("z8", "redis分片操作8");sjedis.setnx("z9", "redis分片操作9");System.out.println("z7:"+sjedis.get("z7"));System.out.println("z8:"+sjedis.get("z8"));System.out.println("z9:"+sjedis.get("z9"));}

结果

2.3 分片机制原理

  1. 一致性哈希算法:Redis的分片机制通常使用一致性哈希算法(Consistent Hashing)来实现。一致性哈希算法将所有的key映射到一个固定的区间上(通常是一个哈希环),然后将这个区间划分为多个片段(shard),每个片段对应一个Redis节点。当客户端请求一个key时,根据一致性哈希算法计算出该key应该属于哪个片段,并将请求发送到对应的节点上进行处理。
  2. 哈希分片:Redis的哈希分片是将键值对通过哈希函数映射到不同的Redis实例中。常用的哈希函数有CRC16和CRC32等。当客户端想要访问某个key时,它会先计算出这个key的哈希值,然后根据哈希值和哈希环的映射关系找到对应的节点进行操作。
  3. 哈希槽(Hash Slots):在Redis的Cluster集群模式中,使用哈希槽的方式来进行数据分片。整个数据集被划分为多个哈希槽,每个哈希槽分配给一个节点。客户端通过计算key的哈希值并取模哈希槽的总数,来确定key所属的哈希槽,进而找到对应的节点进行操作。
  4. 自动故障转移和数据迁移:Redis的分片机制还提供了自动的故障转移和数据迁移机制。当某个节点出现故障或需要扩容时,Redis可以自动地将数据从故障节点迁移到其他节点,以保证系统的可用性和可扩展性。

分片机制存储数据使用的机制:一致性hash算法。

应用场景

场景

N 个 cache 服务器(后面简称 cache ),将一个对象 object 映射到 N 个 cache 上,计算 出object 的 hash 值,均匀的映射到到 N 个 cache ,如key%N,key是object 的hash值,N是服务器节点数

出现的问题

如果有一个服务器加入或退出这个集群,则所有的数据映射都无效了,如果是持久化存储则要做数据迁移,如果是分布式缓存,则其他缓存就失效了

一个服务器宕机退出集群

所有映射到服务器节点的对象都会失效,服务器节点从集群中移除,这时候 集群 是 N-1 台,映射公式变成了 hash(object)%(N-1)

一个服务器加入集群

集群新加服务器节点,这时候 集群 是 N+1 台,映射公式变成了 hash(object)%(N+1) ,所有映射到服务器节点的对象都会失效

解决方案

一致性Hash算法

1.一致性hash算法概述

  • 目的:解决分布式缓存的问题。即解决了简单hash算法在分布式hash表中存在的动态伸缩等问题。
  • 作用:在移除或添加一个服务器时,能够尽可能小地改变已存在的服务语法与处理请求服务器之间的映射关系。

一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响

如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它数据也不会受到影响

2.redis分片机制的一致性hash算法的使用

  • 常规hash运算
    • 结果是由一个8位16进制数构成,共能表示2^32个可能性,根据计算机存储特性(即超出范围即从别一台开始),最后形成一个hash圆。
    • 核心:参与运算的内容,只要运算内容相同,所得的hash运算结果一定相同。
  • 常规hash运算
    • 结果是由一个8位16进制数构成,共能表示2^32个可能性,根据计算机存储特性(即超出范围即从别一台开始),最后形成一个hash圆。
    • 核心:参与运算的内容,只要运算内容相同,所得的hash运算结果一定相同。
  • redis分片机制中的一致性hash算法的使用:只负责数据数据如何管理,不负责存储,存储操作由选取的redis节点负责。
    • 通过分片中的每台redis的信息(ip地址+端口号)进行hash运算来计算出每台redis的节点信息(或者是节点位于2^32具体位置)。
    • redis通过采取k-v结构存储数据。此时在程序中,redis利用传的实参key计算出该条数据位于2^32中的具体位置。
    • redis利用此两类位置信息,按照自定议的方法找到该key距离最近的redis结点,将数据存储在该节点上。
    • 当从redis取出数据时,还是通过key进行hash计算出具体位置,找个具体存储数据的redis节点,取出数据。
    • 具体实现方法如下图所示:

3. 一致性hash的特性

1.平衡性

  • 概念:指hash的结果应该平均分配到各个节点。
  • 作用:从算法上解决负载均衡问题
  • 作用对象:redis节点
  • 实现方式:
    • 当有两个以上redis节点时,两两节点经过hash运算后,位置之间的距离过大时。会在位置过大的两个节点之间生成前一个节点的虚拟节点,该虚拟节点的位置大致会位于两个真实节点位置中点的左侧靠近中点的位置。
    • 一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器,此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点
    • 当保存数据的对应的key经过计算后,位于真实节点与该真实节点的虚拟节点之间是时,该数据将存储到该真实节点中去。
    • 示例:

2.单调性

  • 概念:指新增或删除节点时,不影响系统正常运行。如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区
  • 特点:在进行数据迁移时,要求尽可能小的改变数据。

3.分散性

  • 概念:指数据应该分散的存在在分布式集群中的各个节点,不必每个节点都存储所有的数据。

3、redis哨兵机制

3.1 redis哨兵机制的概述

1.哨兵机制作用

  • 通过哨兵机制实现redis分片的高可用,即在redis的分片中当有一台节点宕机时,不会对整个redis分片的造成影响,从而实现分片的机制的高可用。

2.哨兵机制的实现原理

  • 将多台实现主从结构的redis当做整体。
    • 主机即可读又可写同时会将数据同步到从机中;
    • 而从机平时当作用备用机使用,只接收主机同步的数据,而不接受其它的写操作,但可以接受客户端的读操作;
  • 当主机宕机时,哨兵机制会从从机中选取一台当做主机使用,从而保证整个系统不会因主机宕机而造成访问失败,实现redis高可用。

哨兵通过发送命令(ping命令),等待Redis服务器响应,如果在指定时间内,主机Redis无响应,从机则判断主机宕机,选举从机上位,从而监控运行的多个Redis实例。

第一步:心跳机制

每个 Sentinel 会每秒钟 一次的频率向它所知的 主服务器、从服务器以及其他 Sentinel 实例 发送一个 PING 命令,获取其拓扑结构和状态信息。

第二步:判断master节点是否下线

每个 sentinel 哨兵节点每隔1s向所有的节点发送一个PING命令,作用是通过心跳检测,检测主从服务器的网络连接状态。

如果 master 节点回复 PING 命令的时间超过down-after-milliseconds 设定的阈值(默认30s),则这个 master 会被 sentinel 标记为主观下线。

第三步:基于Raft算法选举领头sentinel

master客观下线,那就需要一个sentinel来负责故障转移,所以需要通过选举一个sentinel的领头羊来解决。

第四步:故障转移

故障转移的一个主要问题和选择领头sentinel问题差不多,就是要选择一个slaver节点来作为master。

选择主Maseter过程大致如下:

①选择优先级最高的节点,通过sentinel配置文件中的replica-priority配置项,这个参数越小,表示优先级越高;

②如果第一步中的优先级相同,选择offset最大的,offset表示主节点向从节点同步数据的偏移量,越大表示同步的数据越多;

③ 如果第二步offset也相同,选择run id较小的;

这样通过以上四大步骤,实现由RedisSentinel自动完成故障发现和转移,实现自动高可用。

第五步:通知

通知所有子节点新的master,后边从新的master上边同步数据;广播通知所有客户端新的master。

3.适用时机

  • 主要针对多台redis构成的实现主从配置或集群里使用。

3.2 哨兵机制的实现

1.准备工作

复制三份redis.conf文件,端口分别为6379,6380,6381

修改如下配置,并启动

bind 127.0.0.1    #主从机设定为统一的端口号绑定
port 6380    #修改成不同的端口号
protected-mode no   #关闭保护模式
daemonize yes   #设置成后台启动
masterauth <master-password>  #如果主机设置了密码,从机中需要添加这个,修改为主机的密码
#启动命令,进入到redis安装目录下
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf

2.主从搭建

  • 节点信息检查命令:
    • 命令格式:info replication
    • 作用:检查redis节点的状态信息
  • 节点划分策略:根据业务需要要求。
    • 示例:以6379为主机、6380、6381为从机
  • 实现主从挂载
    • 方法通过主从挂载命令完成。
    • 主从挂载命令:slaveof host port
    • 实现过程:
      • 第一步:进入从机客户端,执行主从挂载命令

                执行主从挂载后从机信息:

 

                执行主从挂载后主机信息:

3.哨兵机制

  • 原理:
    • 当哨兵工作时会连接redis主机,并通过主机,获取所有从机的信息。
    • 监控主机运行状况
      • 通过心跳检测(pingpong)机制,定时向主机发ping命令,当达到规定次数仍然没有得到主机的pong结果,认定主机宕机。
    • 通过随机算法将从所有从机选举出新主机。
    • 负责剩下的从机重新挂载到新主机上。
    • 当主机恢复后,会做为从机挂载到当前主机上。
  • 哨兵机制的实现
    • 编辑redis.conf文件
    • 编辑sentinel.conf文件
      • 位置:

基础配置方法 

protected-mode no  #关闭保护模式,默认为启动
port 26379   #哨兵工作时的端口,默认为26379
sentinel monitor mymaster 127.0.0.1 6379 1   #哨兵监控的主机信息以及投票次数
#投票次数一般设置为哨兵次数的一半加1即可
#sentinel down-after-milliseconds <master-name> <milliseconds>
#设置主机宕机后到哨兵开始投票之间的时间
#sentinel failover-timeout <master-name> <milliseconds>
#设置投票结果到新主机开始工作之间的时间,如果超过该时间,哨兵视作新主机也宕机,则重新开始投票
  • 哨兵启动与停止
    • 哨兵的启动
      • 前置条件:sentinel.conf
      • 启动命令:redis-sentinel sentinel.conf

进入哨兵客户端及查看相关信息

redis-cli -p 26379
info sentinel

哨兵的停止

redis-cli -p 26379 shutdown

3.3 java整合redis哨兵

- 实现要求:redis哨兵是从哨兵池中获取的。
- 实现步骤:
- 第一步:实现redis池信息配置
- 创建redis池信息配置类JedisPoolConfig的对象。
- 通过setter方法对JedisPoolConfig对象属性赋值完成对redis池配置
- 第二步:指定哨兵主机信息
- 使用Set集合来保存哨兵的主机信息,由此可知哨兵同样可以实现集群。实现方式:
- 第三步:通过redis配置类对象和保存哨兵主机信息的Set对象构建哨兵池:即JedisSentinelPool对象。
- 第四步:从哨兵池(JedisSentinelPool)中获取哨兵,并当做单台Jedis使用。
- 第五步:通过获取的Jedis的对象,操作redis。
- 第六步:使用完毕必须关闭获取的jedis对象。
- 方法:jedis.close();
- 实现示例:

    @Testpublic void testSentinel(){// Redis哨兵的master名称String masterName = "mymaster";// Redis哨兵的hosts列表Set<String> sentinels = new HashSet<String>();sentinels.add("127.0.0.1:26379");
//        sentinels.add("sentinel2-host:port");
//        sentinels.add("sentinel3-host:port");// 创建Jedis哨兵连接池JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sentinels);// 从连接池获取Jedis实例Jedis jedis = sentinelPool.getResource();try {// 使用Jedis实例进行操作,例如设置键值对jedis.set("key", "value");// 获取并打印键对应的值System.out.println(jedis.get("key"));} finally {// 释放Jedis实例到连接池jedis.close();}// 关闭哨兵连接池sentinelPool.close();}

2.springBoot项目整合redis哨兵。

  • 第一步:完成redis哨兵池对象构建并交由spring框架管理。

  • 第二步:完成redis哨兵的DI注入

  • 第三步:获取Jedis对象并通过该对象操作redis
    • 参照单台redis在SpringBoot项目中的应用
  • 第四步:关闭Jedis:jedis.close();

4、redis集群搭建

4.1 redis集群的概述

① 为什么要用集群

通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。

Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿。

由于内存大小的限制,使用一台Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.

采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.

② 集群概念

  • 通过集群机制将哨兵机制的高可用和分片机制的高容量整合到一起,来实现redis的高性能和高可用。

③ 集群优势

  • 采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性。并且在内部实现高可用机制。实现了服务故障的自动迁移。

4.2 redis集群的实现

1.实现需求:准备6台redis,完成3主3从集群搭建,端口号从7000-7005

2.实现步骤:

  • 第一步:复制原始redis.conf文件到指定目录,创建了一个cluster文件夹,文件夹里分别创建7000-7005文件夹,将redis.conf文件分别放到里面

  • 第二步:修改redis.conf
# bind 127.0.0.1  #解除本地ip绑定
protected-mode no   #关闭保护模式
port 7000   #修改端口号为对应端口号,分别是:7000 7001 7002 7003 7004
daemonize yes    #开启后台运行模式
pidfile /usr/local/src/cluster/7000/redis_7000.pid   #是设置pid文件夹,通常和reids.conf位于同一文件夹
dir /usr/local/src/cluster/7000   #设置持久化文件目录,与pid同一目录
maxmemory-policy volatile-lru    #设置内存优化算法
appendonly no    #关闭appendonly持久化策略
cluster-enabled yes   #支持redis集群,必须设置
cluster-config-file nodes-7000.conf    #设置集群配置文件
cluster-node-timeout 15000     #设置集群超时时间,单位毫秒
  • 第三步:开启所有redis
    • 可以通过脚本文件启动所有redis
      • 创建并编辑start.sh
#!/bin/sh
redis-server /usr/local/src/cluster/7000/redis.conf &
redis-server /usr/local/src/cluster/7001/redis.conf &
redis-server /usr/local/src/cluster/7002/redis.conf &
redis-server /usr/local/src/cluster/7003/redis.conf &
redis-server /usr/local/src/cluster/7004/redis.conf &
redis-server /usr/local/src/cluster/7005/redis.conf 

- 通过脚本启动多台redis:

sh start.sh

- 可以通过脚本关闭多台redis:
- 创建stop.sh脚本

#!/bin/sh
redis-cli -p 7000 shutdown &
redis-cli -p 7001 shutdown &
redis-cli -p 7002 shutdown &
redis-cli -p 7003 shutdown &
redis-cli -p 7004 shutdown &
redis-cli -p 7005 shutdown 

- 通过脚本关闭所有redis

sh stop.sh

- 第四步:执行创建集群命令
- 命令自动运行阶段一:收集信息,提出集群创建策略。

redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

- 命令自动运行阶段二:加载节点到集群中

命令自动运行阶段三:完成主从搭建,计算hash槽道,并完成槽道分配

  • 第五步:测试集群

当角色是从机时,仅是备份作用,当其它主机宕机后成为主机,才能按槽道读写;当角色是主机,能读能写,还能向所属从机写入主机数据

集群是根据槽道向主机写入数据,当主机写入数据时,集群会首先计算槽道,按槽道选择所属主机,如果当前主机不是所选主机,则会提示前往对应主机写入数据

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

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

相关文章

纯CSS实现步骤条

纯CSS实现纵向Steps步骤条效果 效果图 实现思路 步骤条是一种用于引导用户按照特定流程完成任务的导航条&#xff0c;在各种分步表单交互场景中广泛应用。步骤条通常由编号、名称和引导线三个基本要素组成。本文中要实现的是一个简单的步骤条&#xff0c;包含上述三个基本要素…

SpringBoot结合Canal 实现数据同步

1、Canal介绍 Canal 指的是阿里巴巴开源的数据同步工具&#xff0c;用于数据库的实时增量数据订阅和消费。它可以针对 MySQL、MariaDB、Percona、阿里云RDS、Gtid模式下的异构数据同步等情况进行实时增量数据同步。 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.…

计算机网络技术主要学什么内容,有哪些课程

计算机网络技术专业是一个涉及理论与实践紧密结合的学科&#xff0c;主要学习内容有计算机网络基础、网络设备技术、网络编程等内容&#xff0c;以下是上大学网&#xff08;www.sdaxue.com&#xff09;整理的计算机网络技术主要学什么内容&#xff0c;供大家参考&#xff01; 基…

20.接口自动化-Git

1、Git和SVN–版本控制系统 远程服务出问题后&#xff0c;可以先提交commit到本地仓库&#xff0c;之后再提交push远程仓库 git有clone Git环境组成部分 常用Git代码仓库服务-远程仓库 GitHub-服务器在国外&#xff0c;慢 GitLab-开源&#xff0c;可以在自己服务器搭建&…

根据docker部署nginx并且实现https

目录 一、Docker中启用HTTPS有几个重要的原因 二、https介绍 三、https过程 四、安装docker-20.10.18 五、如何获取证书 通过阿里云获取证书 六、docker部署nginx并且实现https 6.1准备证书 6.2准备nginx.conf 和 index.html文件 6.3生成容器 6.4浏览器验证证书 一、…

PyTorch的基础用法简介

PyTorch是一个基于Python的开源机器学习库&#xff0c;它提供了灵活的神经网络构建和训练工具。下面是PyTorch的基础用法介绍&#xff1a; 张量&#xff08;Tensors&#xff09;&#xff1a;PyTorch中的基本数据结构是张量&#xff0c;它类似于多维数组。可以通过torch.Tensor…

ssm120基于SSM框架的金鱼销售平台的开发和实现+jsp

金鱼销售平台 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于金鱼销售平台当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了金鱼销售平台&#xff0c;它彻底改…

Oracle一键安装脚本安装教程合集

目前 Oracle 一键安装脚本已经更新到第四代&#xff0c;经作者测试以下版本均可成功安装&#xff01; RedHat/Centos/OracleLinux 6.10 ✅ Oracle 11GR2&#xff08;231017&#xff09;单机Oracle 11GR2&#xff08;231017&#xff09;单机 ASMOracle 11GR2&#xff08;23101…

栈与队列的实现

前言 本次博客将要实现一下栈和队列&#xff0c;好吧 他们两个既可以使用动态数组也可以使用链表来实现 本次会有详细的讲解 栈的实现 栈的基础知识 什么是栈呢&#xff1f; 栈的性质是后进先出 来画个图来理解 当然可不可以出一个进一个呢&#xff0c;当然可以了 比如…

【面试题】音视频流媒体高级开发(2)

面试题6 衡量图像重建好坏的标准有哪些&#xff1f;怎样计算&#xff1f; 参考答案 SNR&#xff08;信噪比&#xff09; PSNR10*log10((2n-1)2/MSE) &#xff08;MSE是原图像与处理图像之间均方误差&#xff0c;所以计算PSNR需要2幅图像的数据&#xff01;&#xff09; SSIM…

Vue路由开启步骤

1.在控制台输入命令 //控制台下载安装npm add vue-router3.6.5 2.在main.js下导入并注册组件 import Vue from vue import App from ./App.vue//控制台下载安装npm add vue-router3.6.5 //导入 import VueRouter from "vue-router";//注册 Vue.use(VueRouter) con…

IntelliJ的Maven编译返回找不到有效证书

文章目录 小结问题及解决找不到有效证书找不到org.springframework.stereotype.Service问题IntelliJ: Cannot resolve symbol springframework 参考 小结 将IntelliJ工程拷贝到新的机器中&#xff0c;返回Maven编译返回找不到有效证书的问题&#xff0c;进行了解决。 问题及解…

实现stract(字符串拼接)函数(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;char a[80], b[80];int i, n1, n2;//填充字符串&#xff1b;printf("请输入字符串a的内…

Python图形界面(GUI)Tkinter笔记(一):根窗口的创建

Tkinter库是Python的内置关于图形界面编程&#xff08;GUI全称为Graphical User Interface&#xff0c;中文意思为“图形用户界面”&#xff09;的一个库。直接导入Tkinter使用即可。 其余笔记&#xff1a;【Python图形界面&#xff08;GUI&#xff09;Tkinter笔记&#xff08;…

蓝桥杯-错误票据(两种写法stringstream和扣字符)

某涉密单位下发了某种票据&#xff0c;并要在年终全部收回。 每张票据有唯一的ID号。 全年所有票据的ID号是连续的&#xff0c;但ID的开始数码是随机选定的。 因为工作人员疏忽&#xff0c;在录入ID号的时候发生了一处错误&#xff0c;造成了某个ID断号&#xff0c;另外一个…

rt-thread 挂载romfs与ramfs

参考&#xff1a; https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/qemu-network/filesystems/filesystems?id%e4%bd%bf%e7%94%a8-romfs https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutor…

React 之 useCallback(缓存函数)(十八)

useCallback 是一个允许你在多次渲染中缓存函数的 React Hook。 useCallback 是一个 Hook&#xff0c;所以应该在 组件的顶层 或自定义 Hook 中调用。你不应在循环或者条件语句中调用它。如果你需要这样做&#xff0c;请新建一个组件&#xff0c;并将 state 移入其中。 //fn&am…

计算机毕业设计 | vue+springboot线上考试 在线测试系统(附源码)

1&#xff0c;项目介绍 项目背景 在线考试借助于网络来进行&#xff0c;传统考试所必备的考场和监考对于在线考试来说并不是必要项目&#xff0c;因此可以有效减少组织考试做需要的成本以及设施。同时&#xff0c;由于在线考试系统本身具有智能阅卷的功能&#xff0c;也大大减…

Sping @Autowired依赖注入原理

Spring 依赖注入发生在bean的实例化之后初始化之前的阶段&#xff0c;可以查看&#xff1a;bean的创建过程 Autowired Autowired由AutowiredAnnotationBeanPostProcessor实现依赖注入。 寻找注入点&#xff1a; AutowiredAnnotationBeanPostProcessor实现了MergedBeanDefin…

Python中的compile()函数,动态编译代码的艺术

关注公众号【一点sir】&#xff0c;领取编程资料。 简介 在Python编程中&#xff0c;compile()函数是一个强大的工具&#xff0c;它允许开发者将字符串形式的Python代码动态编译成字节码。这为执行动态生成或从外部源接收的代码提供了极大的灵活性。这些字节码随后可以被Pytho…