[2024-7-22]面试题2

Redis的持久化机制,在真实的线上环境中需要采取什么样的策略

在真实的线上环境中,Redis的持久化机制主要有两种:RDB(Redis DataBase)和AOF(Append Only File)。每种机制都有其优点和适用场景,实际应用中可以根据需求选择合适的策略,或者结合使用这两种方式。以下是详细的策略建议:

1. RDB 持久化

优点

  • RDB 通过快照机制将数据保存到磁盘上,能够在短时间内快速恢复数据。
  • RDB 文件紧凑,适合做数据备份和迁移。

缺点

  • 由于是定时快照,因此在崩溃的情况下可能会丢失最近一次快照之后的数据。
  • 大规模数据快照时,可能会影响Redis的性能。

使用建议

  • 适用于数据变化不频繁的场景。

  • 可以通过配置save参数来定时生成快照,例如:

    save 900 1   # 每15分钟如果至少有1个key发生变化,则生成快照
    save 300 10  # 每5分钟如果至少有10个key发生变化,则生成快照
    save 60 10000 # 每1分钟如果至少有10000个key发生变化,则生成快照
    
  • 使用stop-writes-on-bgsave-error确保在快照出错时停止写操作,避免数据损坏。

2. AOF 持久化

优点

  • AOF 通过记录每个写操作日志来实现数据持久化,提供更高的数据安全性。
  • 支持三种同步策略:每个写操作同步、每秒同步、操作系统控制同步,灵活性高。

缺点

  • AOF 文件相对较大,恢复时间可能较长。
  • 写操作频繁时,可能对Redis性能有一定影响。

使用建议

  • 适用于需要高数据安全性的场景。

  • 配置appendfsync参数来调整同步策略:

    appendfsync always   # 每个写操作都同步(最安全,但性能最低)
    appendfsync everysec # 每秒同步一次(折中方案,推荐使用)
    appendfsync no       # 由操作系统决定何时同步(性能最高,但可能丢失数据)
    
  • 配置no-appendfsync-on-rewrite来避免在重写AOF文件时阻塞写操作:

    no-appendfsync-on-rewrite yes
    

3. RDB 和 AOF 结合使用

策略

  • 同时启用RDB和AOF,以兼顾数据恢复速度和数据安全性。

  • 在配置文件中同时开启RDB和AOF:

    save 900 1
    save 300 10
    save 60 10000appendonly yes
    appendfsync everysec
    
  • 定期备份RDB文件,以便在AOF文件损坏时也能快速恢复数据。

4. 备份和监控

建议

  • 定期备份RDB文件和AOF文件,存储在安全的地方。
  • 使用Redis提供的INFO命令和监控工具(如Prometheus、Grafana)监控Redis性能和持久化状态。
  • 配置日志文件监控,及时发现并处理持久化过程中的异常情况。

通过以上策略,可以根据具体的应用场景和需求,选择合适的持久化机制,确保Redis在线上环境中的数据安全和高效运行。如果有具体的需求或遇到特殊问题,欢迎进一步讨论。

RDB 和 AOF 结合使用是不是线上环境最优解

在实际生产环境中,RDB 和 AOF 结合使用通常被认为是最佳实践,因为它可以同时利用两种持久化机制的优点,提供数据的安全性和较快的恢复速度。以下是两者结合使用的优点及其配置建议:

结合使用的优点

  1. 数据安全性

    • AOF 记录每个写操作日志,保证数据的持久性和完整性。在Redis意外宕机的情况下,能最大限度地减少数据丢失。
    • RDB 提供周期性的完整数据快照,便于快速恢复大量数据。
  2. 恢复速度

    • RDB 文件在数据恢复时比AOF文件更快,因为RDB文件是数据的二进制快照,而AOF需要重放所有写操作。
    • 结合使用可以在灾难恢复时先加载RDB文件,然后重放AOF日志,从而达到快速且相对完整的数据恢复效果。
  3. 性能优化

    • 定期生成RDB快照的过程中可以减小AOF文件的大小,从而降低AOF重写的开销。
    • 在进行AOF重写时,如果有RDB作为备用,可以有效降低Redis在重写期间的性能影响。

配置建议

以下是一个结合使用RDB和AOF的示例配置:

# RDB配置
save 900 1     # 每15分钟如果至少有1个key发生变化,则生成快照
save 300 10    # 每5分钟如果至少有10个key发生变化,则生成快照
save 60 10000  # 每1分钟如果至少有10000个key发生变化,则生成快照
stop-writes-on-bgsave-error yes # 快照出错时停止写操作# AOF配置
appendonly yes       # 开启AOF持久化
appendfsync everysec # 每秒同步一次,平衡性能和数据安全性
no-appendfsync-on-rewrite yes # 在AOF重写期间不进行追加同步# 其他建议
auto-aof-rewrite-percentage 100  # AOF文件增长100%时触发重写
auto-aof-rewrite-min-size 64mb   # AOF文件最小64MB时触发重写

备份和监控

  1. 定期备份

    • 定期备份RDB文件和AOF文件,并将备份存储在安全的地方(如远程存储或云存储)。
    • 备份可以通过脚本定时执行,如使用cron作业。
  2. 监控

    • 使用Redis的INFO命令监控持久化状态和性能指标。
    • 使用监控工具(如Prometheus和Grafana)可视化Redis的运行状态,设置告警机制及时发现问题。
    • 配置日志文件监控,及时处理持久化过程中可能出现的错误和异常。

通过以上策略,结合使用RDB和AOF,可以提供良好的数据持久化保障,确保在生产环境中Redis的稳定性和可靠性。如果有特殊的需求或遇到特定问题,随时可以讨论以找到更合适的解决方案。

AOF的持久化机制是如何实现的?

Redis 的 AOF(Append Only File)持久化机制通过记录每个写操作日志来实现数据的持久化。具体实现步骤如下:

1. 记录写操作

每当有写操作(如 SETLPUSHSADD 等)时,Redis 会将这个操作以命令的形式追加到 AOF 文件的末尾。每个操作都会以 Redis 命令的文本形式记录。例如:

*3
$3
SET
$3
key
$5
value

2. 同步策略

Redis 提供三种同步策略来控制 AOF 文件何时同步到磁盘:

  • always:每次写操作都立即同步到磁盘。这种方式最安全,但性能最低。
  • everysec:每秒同步一次,折衷了性能和数据安全性。
  • no:由操作系统决定何时同步,性能最好,但在系统崩溃时可能会丢失最近的写操作。

可以通过 appendfsync 参数配置同步策略:

appendfsync always
appendfsync everysec
appendfsync no

3. AOF 重写

随着时间的推移,AOF 文件会不断增长,变得非常大。为了避免文件过大,Redis 提供了 AOF 重写机制,通过创建一个新的 AOF 文件,仅包含生成当前数据集所需的最小命令集。具体步骤如下:

  1. 触发重写:当 AOF 文件增长到一定大小时(由 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 参数控制),Redis 会触发 AOF 重写。

    auto-aof-rewrite-percentage 100  # AOF 文件大小达到上次重写时的100%时触发重写
    auto-aof-rewrite-min-size 64mb   # AOF 文件最小64MB时触发重写
    
  2. 创建新文件:Redis 创建一个新的 AOF 文件,通过读取当前内存中的数据,生成最小的命令集写入新文件。这些命令集可以通过重新执行来重建当前数据集。

  3. 写操作缓冲:在重写过程中,Redis 会将新的写操作暂时缓存在内存中,确保新旧文件的一致性。

  4. 文件替换:当新文件生成完毕后,Redis 会将新的 AOF 文件替换旧的 AOF 文件,并将缓存在内存中的写操作追加到新文件中。

4. AOF 文件加载

在Redis启动时,如果配置了 AOF 持久化,Redis 会首先加载 AOF 文件中的命令来重建数据集:

  1. 读取文件:Redis 按顺序读取 AOF 文件中的命令。
  2. 重放命令:逐条执行这些命令,重建数据集。

配置示例

以下是一个典型的 AOF 配置示例:

appendonly yes             # 开启 AOF 持久化
appendfsync everysec       # 每秒同步一次
no-appendfsync-on-rewrite yes  # 在 AOF 重写期间不进行追加同步# 自动重写配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

总结

AOF 通过记录每个写操作的命令日志,确保数据持久化和可靠性。结合适当的同步策略和重写机制,AOF 提供了良好的数据安全性和性能平衡。

SpringBoot中的@Autowried 是如何注入的?

在Spring Boot中,@Autowired注解用于自动注入依赖。它是通过Spring的依赖注入(Dependency Injection,DI)机制实现的。下面详细解释其工作原理及注入过程:

1. 依赖注入概述

Spring的依赖注入有两种主要方式:

  • 构造器注入:通过类的构造函数注入依赖。
  • 属性注入:通过类的属性注入依赖。

@Autowired可以用于构造器、属性和方法来自动注入依赖。

2. @Autowired 注解的使用

  • 属性注入

    @Component
    public class MyService {@Autowiredprivate MyRepository myRepository;// other methods
    }
    
  • 构造器注入

    @Component
    public class MyService {private final MyRepository myRepository;@Autowiredpublic MyService(MyRepository myRepository) {this.myRepository = myRepository;}// other methods
    }
    
  • 方法注入

    @Component
    public class MyService {private MyRepository myRepository;@Autowiredpublic void setMyRepository(MyRepository myRepository) {this.myRepository = myRepository;}// other methods
    }
    

3. 自动注入过程

3.1. Spring 容器的初始化

当Spring容器启动时,它会扫描并实例化所有带有@Component@Service@Repository@Controller等注解的类。这些类的实例被称为Spring Bean,并被Spring容器管理。

3.2. 依赖解析

Spring容器会解析每个Bean的依赖。在解析过程中,它会检查Bean类的字段、构造器和方法上是否有@Autowired注解。

3.3. 依赖注入
  • 属性注入
    Spring容器会查找需要注入的依赖类型的Bean实例,并将其注入到带有@Autowired注解的字段中。

  • 构造器注入
    Spring容器会调用带有@Autowired注解的构造器,传递所需的依赖Bean实例。

  • 方法注入
    Spring容器会调用带有@Autowired注解的方法,传递所需的依赖Bean实例。

3.4. 处理循环依赖

Spring通过三级缓存(SingletonFactories、EarlySingletonObjects、SingletonObjects)机制解决循环依赖问题:

  1. SingletonObjects:已经完全初始化的单例对象。
  2. EarlySingletonObjects:正在创建中的单例对象,可以解决循环引用问题。
  3. SingletonFactories:用于创建单例对象的工厂,可以避免AOP代理问题。

4. 详细工作流程

  1. 扫描组件
    Spring扫描带有@Component@Service等注解的类,并将其注册为Bean。

  2. 创建Bean
    Spring按照需要创建Bean实例,并保存到三级缓存中。

  3. 依赖注入

    • Spring检查@Autowired注解。
    • 从容器中获取需要注入的Bean。
    • 将获取到的Bean注入到目标Bean中。
  4. 处理循环依赖

    • 利用三级缓存,首先创建代理对象放入缓存,然后解决依赖,最后初始化完成。

示例

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;// other methods
}@Component
public class ServiceB {@Autowiredprivate ServiceA serviceA;// other methods
}

在上述示例中,ServiceAServiceB相互依赖。Spring容器通过三级缓存机制处理这种循环依赖,确保两个Bean都能成功实例化并注入对方。

总结

@Autowired注解通过Spring的依赖注入机制,自动将所需的Bean注入到目标Bean中。Spring容器负责扫描、实例化、解析和注入依赖,确保Bean之间的依赖关系正确无误。通过三级缓存机制,Spring还能有效处理循环依赖问题。

RabbitMQ如何保证消息不丢失

RabbitMQ是一种可靠的消息队列系统,通过以下几种方式来保证消息不丢失:

1. 使用持久化消息队列(Durable Queues)

  • 配置队列为持久化:在声明队列时设置durable属性为true,确保队列在RabbitMQ服务器重启后依然存在。

    channel.queueDeclare("myQueue", true, false, false, null);
    

2. 使用持久化消息(Persistent Messages)

  • 配置消息为持久化:在发送消息时,将MessagePropertiesPERSISTENT_TEXT_PLAIN属性设置为true,确保消息在RabbitMQ服务器重启后依然存在。

    channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
    

3. 消息确认(Message Acknowledgements)

  • 启用手动消息确认:消费者在处理消息后发送确认(acknowledgement),确保消息被成功处理后再从队列中删除。

    boolean autoAck = false; // 关闭自动确认
    channel.basicConsume("myQueue", autoAck, consumerTag, new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String message = new String(body, "UTF-8");try {// 处理消息channel.basicAck(envelope.getDeliveryTag(), false); // 手动确认消息} catch (Exception e) {channel.basicNack(envelope.getDeliveryTag(), false, true); // 处理失败时重新入队}}
    });
    

4. 发布确认(Publisher Confirms)

  • 启用发布确认模式:生产者在发送消息后等待RabbitMQ的确认,确保消息被正确写入队列。

    channel.confirmSelect(); // 启用发布确认模式channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());if (!channel.waitForConfirms()) {// 处理未确认的消息
    }
    

5. 高可用模式(High Availability)

  • 使用镜像队列(Mirrored Queues):配置队列为镜像队列,确保队列和消息在多个节点上存在副本,提高可用性和容错性。

    rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
    

6. 死信队列(Dead Letter Queues)

  • 配置死信队列:为队列设置死信交换机和死信路由键,当消息因超时或被拒绝时,消息会被转发到死信队列,以便后续处理。

    Map<String, Object> args = new HashMap<String, Object>();
    args.put("x-dead-letter-exchange", "dlx-exchange");
    args.put("x-dead-letter-routing-key", "dlx-routing-key");
    channel.queueDeclare("myQueue", true, false, false, args);
    

7. 持久化存储(Persistent Storage)

  • 使用磁盘存储消息:RabbitMQ默认将持久化消息存储在磁盘上,确保在系统崩溃时消息不会丢失。

8. 定期备份

  • 定期备份RabbitMQ数据:通过定期备份RabbitMQ的数据文件来防止数据丢失。

综合应用

为了保证消息不丢失,通常会结合以上多种方法。例如,配置持久化队列和消息、启用手动确认和发布确认、使用镜像队列和死信队列等。

配置示例

以下是一个综合使用这些方法的示例代码:

// 配置队列为持久化
channel.queueDeclare("myQueue", true, false, false, null);// 配置消息为持久化
channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());// 启用发布确认模式
channel.confirmSelect();
channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
if (!channel.waitForConfirms()) {// 处理未确认的消息
}// 启用手动消息确认
boolean autoAck = false;
channel.basicConsume("myQueue", autoAck, new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String message = new String(body, "UTF-8");try {// 处理消息channel.basicAck(envelope.getDeliveryTag(), false);} catch (Exception e) {channel.basicNack(envelope.getDeliveryTag(), false, true);}}
});// 配置死信队列
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx-exchange");
args.put("x-dead-letter-routing-key", "dlx-routing-key");
channel.queueDeclare("myQueue", true, false, false, args);// 配置镜像队列
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}';

通过以上配置,RabbitMQ可以有效地保证消息在各种异常情况下不丢失。

如何配置一个延时队列

在RabbitMQ中配置一个延时队列可以通过使用死信交换机(Dead Letter Exchange, DLX)和消息TTL(Time-To-Live)来实现。具体步骤如下:

1. 配置延时队列和死信交换机

延时队列设置消息的TTL属性,使得消息在一定时间后到期,并被路由到死信交换机。死信交换机将消息转发到实际的处理队列。

2. 配置示例

以下是一个使用RabbitMQ Java客户端(如com.rabbitmq.client库)的示例代码:

2.1. 声明交换机和队列
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;import java.util.HashMap;
import java.util.Map;public class DelayedQueueSetup {private static final String EXCHANGE_NAME = "exchange.delayed";private static final String QUEUE_NAME = "queue.delayed";private static final String DLX_NAME = "exchange.dlx";private static final String DLX_QUEUE_NAME = "queue.dlx";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 声明死信交换机channel.exchangeDeclare(DLX_NAME, "direct");channel.queueDeclare(DLX_QUEUE_NAME, true, false, false, null);channel.queueBind(DLX_QUEUE_NAME, DLX_NAME, "routingKey.dlx");// 声明延时队列并绑定死信交换机Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", DLX_NAME);args.put("x-dead-letter-routing-key", "routingKey.dlx");args.put("x-message-ttl", 10000); // 消息在延时队列中的存活时间(毫秒)channel.queueDeclare(QUEUE_NAME, true, false, false, args);channel.exchangeDeclare(EXCHANGE_NAME, "direct");channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingKey.delayed");// 发送消息String message = "Hello, this is a delayed message!";channel.basicPublish(EXCHANGE_NAME, "routingKey.delayed", null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");// 消费消息channel.basicConsume(DLX_QUEUE_NAME, true, (consumerTag, delivery) -> {String receivedMessage = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + receivedMessage + "'");}, consumerTag -> { });}}
}

3. 配置说明

  • 声明死信交换机和死信队列

    channel.exchangeDeclare(DLX_NAME, "direct");
    channel.queueDeclare(DLX_QUEUE_NAME, true, false, false, null);
    channel.queueBind(DLX_QUEUE_NAME, DLX_NAME, "routingKey.dlx");
    
  • 声明延时队列并绑定到死信交换机

    Map<String, Object> args = new HashMap<>();
    args.put("x-dead-letter-exchange", DLX_NAME);
    args.put("x-dead-letter-routing-key", "routingKey.dlx");
    args.put("x-message-ttl", 10000); // 消息的存活时间,单位为毫秒channel.queueDeclare(QUEUE_NAME, true, false, false, args);
    channel.exchangeDeclare(EXCHANGE_NAME, "direct");
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingKey.delayed");
    
  • 发送消息到延时队列

    String message = "Hello, this is a delayed message!";
    channel.basicPublish(EXCHANGE_NAME, "routingKey.delayed", null, message.getBytes());
    
  • 消费消息
    消费从死信队列中转发的消息:

    channel.basicConsume(DLX_QUEUE_NAME, true, (consumerTag, delivery) -> {String receivedMessage = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + receivedMessage + "'");
    }, consumerTag -> { });
    

4. 运行代码

运行以上代码,将会在延时队列中发送一条消息,经过指定的TTL时间(在此示例中为10秒)后,消息会被转发到死信交换机,并最终到达实际的处理队列(死信队列)。

总结

通过使用消息的TTL和死信交换机机制,可以在RabbitMQ中轻松实现延时队列。该方法通过在消息到期后将其路由到死信交换机,实现消息的延迟处理。这种方法简单易行,且不需要额外的插件或扩展。

Mysql死锁

MySQL中的死锁是指两个或多个事务在持有某些资源的同时,等待对方持有的资源,从而形成循环等待的现象。死锁会导致这些事务无法继续执行下去,必须通过某种机制来解决。以下是MySQL中常见的导致死锁的原因、检测和解决方案。

常见的导致死锁的原因

  1. 不同顺序的锁请求

    • 如果两个事务按不同的顺序请求相同的资源,可能会导致死锁。
    • 例如,事务A先锁表T1然后锁表T2,而事务B先锁表T2然后锁表T1。
  2. 长事务

    • 长时间运行的事务持有锁的时间较长,增加了发生死锁的可能性。
  3. 大范围的更新或删除操作

    • 大范围的更新或删除操作会锁定较多的行,增加了发生死锁的可能性。
  4. 外键和触发器

    • 使用外键约束和触发器可能会导致隐式锁定,增加了发生死锁的可能性。

检测死锁

MySQL能够自动检测死锁,并回滚其中一个事务以解除死锁。可以通过以下方法来检测死锁:

  1. 通过日志文件检测

    • MySQL会将死锁信息记录到错误日志文件中,可以通过查看错误日志来检测死锁。
  2. 通过命令检测

    • 使用以下命令查看当前的InnoDB状态,其中包括死锁信息:
      SHOW ENGINE INNODB STATUS;
      
    • 输出的结果中会包含最近一次死锁的信息。

解决死锁的策略

  1. 调整事务顺序

    • 尽量使所有事务以相同的顺序请求资源,以减少死锁的可能性。
    • 例如,所有事务都先锁表T1然后锁表T2。
  2. 减少事务持有锁的时间

    • 尽量缩短事务的执行时间,避免长时间持有锁。
    • 将大事务拆分为多个小事务。
  3. 合理使用索引

    • 确保在查询中使用索引,以减少锁定的行数。
    • 尽量避免大范围的全表扫描。
  4. 捕获并处理死锁异常

    • 在应用程序中捕获并处理死锁异常,回滚被回滚的事务并重试。
    • 例如,使用Java中的Spring框架,可以配置重试机制来处理死锁。
  5. 使用合理的隔离级别

    • 在保证数据一致性的前提下,选择较低的隔离级别,如READ COMMITTED,以减少锁的争用。
    • 例如:
      SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
      

示例代码

以下是一个示例,展示如何在Java应用中使用Spring框架捕获并处理死锁异常:

import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;public class MyService {private final JdbcTemplate jdbcTemplate;public MyService(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Transactionalpublic void updateData() {boolean success = false;int retries = 3;while (!success && retries > 0) {try {// 执行数据库操作jdbcTemplate.update("UPDATE my_table SET column1 = ? WHERE column2 = ?", value1, value2);success = true;} catch (DeadlockLoserDataAccessException e) {// 捕获死锁异常并重试retries--;if (retries == 0) {throw e; // 达到重试次数,抛出异常}}}}
}

总结

MySQL中的死锁是由于事务竞争资源导致的。通过合理设计事务顺序、减少锁持有时间、使用索引、捕获并处理死锁异常,以及选择适当的隔离级别,可以有效减少和解决死锁问题。在实际应用中,结合日志和状态信息检测死锁,及时采取措施,是保障系统稳定性和性能的重要手段。

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

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

相关文章

Synopsys:Design Compiler的XG模式和DB模式

相关阅读 Synopsyshttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 很久之前&#xff0c;Design Compiler使用的是DB模式&#xff08;包括一些其他工具&#xff0c;例如DFT Compiler, Physical Compiler和Power Compiler&#xff09;&…

二叉树基础及实现(一)

目录&#xff1a; 一. 树的基本概念 二. 二叉树概念及特性 三. 二叉树的基本操作 一. 树的基本概念&#xff1a; 1 概念 &#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因…

数据结构之初始二叉树(4)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 二叉树的基本操作 二叉树的相关刷题&#xff08;上&#xff09;通过上篇文章的学习&#xff0c;我们…

queue的模拟实现【C++】

文章目录 全部的实现代码放在了文章末尾什么是适配器模式&#xff1f;准备工作包含头文件定义命名空间类的成员变量 默认成员函数emptysizefrontbackpushpop全部代码 全部的实现代码放在了文章末尾 queue的模拟实现和stack一样&#xff0c;采用了C适配器模式 queue的适配器一…

Leetcode 3229. Minimum Operations to Make Array Equal to Target

Leetcode 3229. Minimum Operations to Make Array Equal to Target 1. 解题思路2. 代码实现 题目链接&#xff1a;3229. Minimum Operations to Make Array Equal to Target 1. 解题思路 这一题其实也还蛮简单的&#xff0c;我们只需要考察一下两个数组的差值序列即可。 我…

PCI总线域与处理器域

PCI总线域 在x86处理器系统中&#xff0c;PCI总线域是外部设备域的重要组成部分。实际上在Intel的x86处理器系统中&#xff0c;所有的外部设备都使用PCI总线管理。而AMD的x86处理器系统中还存在一条HT(HyperTransport)总线&#xff0c;在AMD的x86处理器系统中还存在HT总线域。…

Java生成四位纯数字并且确保唯一性

背景&#xff1a; 给了我一个需求&#xff0c;由于某些问题原因&#xff0c;需要给属性和数据添加一个code字段&#xff0c;这是给我发的消息 这两个要求其实是同一个需求&#xff0c;就是在创建对象的时候塞入一个unique的code嘛&#xff0c;听起来很简单吧&#xff0c;但是实…

GooglePlay 金融品类政策更新(7月17号)

距离上次政策大更新&#xff08;4月5号&#xff09;才过去了3个月&#xff0c;Google Play又迎来了一次大更新&#xff0c;不得不说Google Play的要求越来越高了。 我们来梳理一下这次GooglePlay针对金融品类更新了哪些政策: 1.要求提供金融产品和服务的开发者必须注册为组织…

Window环境下MySQL管理

1、MySQL服务启用和停止 图形化界面管理 使用键盘组合键&#xff08;Win R&#xff09;打开运行对话框&#xff0c;在对话框中输入services.msc并点击确定。 这里可以看到服务名称为MySQL84并处于正在运行的状态。 选中后右键可以进行暂停、停止、重启等操作。 命令提示符管理…

OpenCV 直方图概念,直方图均衡化原理详解

文章目录 直方图相关概念颜色灰度级作用应用场景 C 使用OpenCV绘制直方图单通道直方图关键代码分析&#xff1a;calcHist函数分析使用OpenCV API来绘制直方图 效果图&#xff1a; 彩色三通道直方图效果图&#xff1a; 直方图均衡化概念均衡化作用均衡化效果均衡化数学原理步骤数…

杭电第一场

洛谷的评测地 循环位移 哈希&#xff0c;已知开头和长度&#xff0c;利用哈希相减得出该段是否为一个A串的循环 #include <bits/stdc.h> #pragma GCC optimize(2) using namespace std; using i64 long long; using pii pair<int,int>;const int m1 1e9 7, …

Linux中进程间通信--匿名管道和命名管道

本篇将会进入 Linux 进程中进程间通信&#xff0c;本篇简要的介绍了 Linux 中进程为什么需要通信&#xff0c;进程间通信的常用方式。然后详细的介绍了 Linux 进程间的管道通信方式&#xff0c;管道通信分为匿名管道和命名管道&#xff0c;本篇分别介绍了其实现的原理&#xff…

基于VMware(虚拟机) 创建 Ubunton24.04

目录 1.设置 root 密码 2. 防火墙设置 2.1 安装防火墙 2.2 开启和关闭防火墙 2.3 开放端口和服务规则 2.4 关闭端口和删除服务规则 2.5 查看防火墙状态 3. 换源 3.1 源文件位置 3.2 更新软件包 1. 设置网络 1. 在安装ubuntu时设置网络 2.在配置文件中修改 2.设置 r…

17_高级进程间通信 UNIX域套接字1

非命名的UNIX域套接字 第1个参数domain&#xff0c;表示协议族&#xff0c;只能为AF_LOCAL或者AF_UNIX&#xff1b; 第2个参数type&#xff0c;表示类型&#xff0c;只能为0。 第3个参数protocol&#xff0c;表示协议&#xff0c;可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STR…

(二刷)代码随想录第23天|538.把二叉搜索树转换为累加树 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树

538.把二叉搜索树转换为累加树 观察实例可以看出二叉树的遍历顺序为右中左: 递归三部曲&#xff1a; class Solution {// 将 sum 定义为类的成员变量int sum;public TreeNode convertBST(TreeNode root) {sum 0; // 初始化 sum 为 0convertBST1(root);return root; …

HTTP 缓存

缓存 web缓存是可以自动保存常见的文档副本的HTTP设备&#xff0c;当web请求抵达缓存时&#xff0c;如果本地有已经缓存的副本&#xff0c;就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…

Leetcode617. 两个二叉树相加

题目描述 和leetcode226.翻转二叉树非常相似&#xff0c;核心还是递归。 答案&#xff1a; class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if (root1 null) {return root2;}if (root2 null) {return root1;}TreeNode root new TreeNode();…

MySQL学习之InnoDB引擎,索引

Mysql中的引擎 我们先来看一下MySql提供的有哪些引擎 mysql> show engines; 从上图我们可以查看出 MySQL 当前默认的存储引擎是InnoDB,并且在5.7版本所有的存储引擎中只有 InnoDB 是事务性存储引擎&#xff0c;也就是说只有 InnoDB 支持事务。 查看MySQL当前默认的存储引…

QtQuick-QML类型系统-对象类型

数据类型可以是QML语言原生的&#xff0c;可以通过C注册&#xff0c;可以由独立的QML文档作为模块进行加载&#xff0c;也可以由开发者通过C类型或者定义QML组件来提供自定义的类型。 不过&#xff0c;无论如何&#xff0c;QML引擎都会保证这些类型的属性和实例的类型安全。 …

@DateTimeFormat 和 @JsonFormat 注解详解

DateTimeFormat 和 JsonFormat 注解详解 在 Java 开发尤其是基于 Spring 的项目中&#xff0c;日期和时间的处理是必不可少的一部分。DateTimeFormat 和 JsonFormat 这两个注解被广泛用于日期和时间的格式化处理。本文将深入探讨这两个注解的使用场景、差异及实践应用。 1. 基…