MySQL原理(六):日志

news2024/9/21 19:51:20

前言

上一篇介绍了 MySQL 的锁,这一篇将介绍日志相关的内容。

MySQL 中最常见的日志有三类:

  • undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC
  • redo log(重做日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于故障恢复
  • binlog (归档日志):是 Server 层生成的日志,主要用于数据备份和主从复制

undo log

当一条写入类型的 SQL 执行时,都会记录一条 undo log 日志,生成相反的 SQL,比如执行一条 insert 语句后会生成一条对应的 delete 的 SQL 语句在 undo log 中。在事务回滚时,只需要按顺序执行 undo log 中的语句。

每条 undo log 都有一个 roll_pointer 指针和一个事务id trx_id:

  • 通过 trx_id 可以知道该记录是被哪个事务修改的;
  • 通过 roll_pointer 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;

在这里插入图片描述

undo log 存储在 Undo 表空间中(.ibdata 格式文件),其中有一块区域名为 Rollback Segment(回滚段),每个回滚段中有 1024 个 Undo-log Segment,每个 Undo-log Segment 可存储一条数据,默认有 128 个回滚段,即支持 128*1024 条记录同时存在。

undo log 两大作用:

  • 实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
  • 实现 MVCC(多版本并发控制)关键因素之一。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 ReadView 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

为什么 undo log 不像 redo log 和 binlog 一样,有缓存(redo log buffer、binlog cache)?

因为 undo log 需要实现事务回滚,如果先存入一个缓冲区,会由于 MySQL 崩溃而丢失。

insert undo log

在这里插入图片描述

对于 insert 类型的 SQL,会在 undo log 中记录下刚插入进来的数据 ID,根据 ID 完成删除。

有多个主键是为了解决联合主键的情况。

因为单纯的插入不涉及 MVCC,所以一旦事务提交,这条 insert undo log 就可以直接删除了。

update undo log

在这里插入图片描述

delete 语句使用的也是 update undo log。

持久化

undo log 类似于数据,其管理和落盘策略和数据页是一样的,都需要通过 redo log 保证持久化。

  • undo log 的磁盘结构并不是顺序的,而是像数据一样按页管理;
  • undo log 写入时,也像数据一样产生对应的 redo log;
  • undo log 的页也像数据一样缓存在 Buffer Pool 中,跟数据页一起做 LRU 换入换出,以及刷脏;
  • 对 undo 页的修改也都会记录到 redo log;
  • undo 页的刷脏也像数据一样要等到对应的 redo log 落盘之后;

redo log

MySQL 中的数据是存储在磁盘上的,但是如果每次读写数据都通过磁盘的话,读写的效率会非常低,所以 InnoDB 在内存中设置了一个区域 Buffer Pool,可以直接通过内存来读取和修改数据,后续再将内存中的数据更新到磁盘中。但是内存中的数据是易失性的,可能随着进程、系统崩溃等情况而丢失,所以 MySQL 设计了 redo log 来解决这类问题。

当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(修改 Buffer Pool 中的数据页,同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来(持久化到磁盘),这个时候更新就算完成了。后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术

WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上

redo log 主要用于故障恢复(重做),即恢复到故障发生前的状态。

修改缓存(Buffer Pool)中的页面后也需要记录对应的 redo log。

redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?

写入 redo log 的方式使用了追加操作, 磁盘操作是顺序写;而写入数据需要先找到写入位置,再写到磁盘,磁盘操作是随机写

磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。

如果 redo log 提交完成了,事务就不能回滚,因为可能覆盖掉别的事务的更新。所以虽然 undo log 表示更新前,redo log 表示更新后,但一个用于回滚,一个用于故障恢复。

redo log block

redo log 是按块,一块块地写入到磁盘中去的。同一个事务产生的 redo log 会被标记为一个 redo log group,持续写入到 redo log block 中。

由 N 个大小相同的 redo log 组成一个 redo log group。N 的值默认为 2。

在这里插入图片描述

redo log buffer

redo log 是先写入内存的 redo log buffer 中,再按照不同的持久化策略写入到磁盘中。

redo log buffer 中会划分出多个 rodo log block。redo log buffer 占用一块连续的内存空间(在 buffer pool 中),默认大小为 16MB。

在这里插入图片描述

持久化

redo log 并不是直接写入磁盘的,而是先写入到 redo log buffer(内存中),后续再持久化到磁盘。

持久化到磁盘主要有以下几个时机:

  • MySQL 正常关闭时;
  • 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
  • InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
  • 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(由 innodb_flush_log_at_trx_commit 参数控制)。

innodb_flush_log_at_trx_commit 可取的值有 0、1、2。

  • 0:每次事务提交时 ,将 redo log 留在 redo log buffer 中 ,该模式下在事务提交时不会主动触发写入磁盘的操作。
  • 1:每次事务提交时,将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘,可以保证 MySQL 异常重启之后数据不会丢失。
  • 2:每次事务提交时,将缓存在 redo log buffer 里的 redo log 写到 Page Cache,即操作系统的文件缓存。

在这里插入图片描述

innodb_flush_log_at_trx_commit 为 0 和 2 的时候,什么时候才将 redo log 写入磁盘?

InnoDB 的后台线程每隔 1 秒:

  • 针对参数 0 :会把缓存在 redo log buffer 中的 redo log ,通过调用 write() 写到操作系统的 Page Cache,然后调用 fsync() 持久化到磁盘。所以参数为 0 的策略,MySQL 进程的崩溃会导致上一秒钟所有事务数据的丢失
  • 针对参数 2 :调用 fsync,将缓存在 Page Cache 里的 redo log 持久化到磁盘。所以参数为 2 的策略,较取值为 0 情况下更安全,因为 MySQL 进程的崩溃并不会丢失数据,只有在操作系统崩溃或者系统断电的情况下,上一秒钟所有事务数据才可能丢失

在这里插入图片描述

这三个参数的数据安全性和写入性能的比较如下:

  • 数据安全性:参数 1 > 参数 2 > 参数 0
  • 写入性能:参数 0 > 参数 2> 参数 1

循环写

InnoDB 存储引擎有一个 redo log group,由两个 redo log 文件组成。两个文件的大小固定且一致。

redo log 是以循环写的方式工作的,从头开始写,写到末尾就又回到开头,相当于一个环形。

如果 Buffer Pool 的脏页刷新到了磁盘中,那么 redo log 对应的记录也就没用了,这时候需要擦除这些旧记录,以腾出空间记录新的更新操作。

在这里插入图片描述

  • write pos 表示 redo log 当前记录写到的位置,check point 表示当前要擦除的位置;
  • write pos 和 check point 的移动都是顺时针方向;
  • write pos ~ check point 之间的部分(红色部分),用来记录新的更新操作;
  • check point ~ write pos 之间的部分(蓝色部分),表示待落盘的脏数据页记录;

如果 write pos 追上了 check point,就意味着 redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞,此时会停下来将 Buffer Pool 中的脏页刷新到磁盘中,然后标记 redo log 哪些记录可以被擦除,接着对旧的 redo log 记录进行擦除,等擦除完旧记录腾出了空间,check point 就会往后移动,然后 MySQL 恢复正常运行,继续执行新的更新操作。

binlog

binlog 中记录了所有对数据库表结构表更和数据修改的操作,主要用于数据备份和主从复制。binlog 是 Server 层实现的,所有存储引擎都能使用。而 undo log 和 redo log 是 InnoDB 实现的。

在完成一条更新操作后,Server 层还会生成一条 binlog,等事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写入 binlog 文件。

binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。

格式

binlog 有三种格式:statement、row、mixed。

Statement

statement 格式下,记录到 binlog 里的是语句原文。可能会出现主库和从库执行结果不一样的情况。

在这里插入图片描述

Row

row 格式下的 binlog 里面记录了真实删除行的主键id,这样就不会出现主备执行结果不一样。且对每一行数据的修改比 statement 格式更高效。

在误删改数据后,且无备份可以恢复时,可以通过分析 binlog 日志进行反向处理达到恢复数据目的。

row 格式的缺点是很占空间,且 IO 开销更大。比如删除十万条数据,用 statement 格式的话就是一个 SQL 语句,而用 row 格式就需要把十万条记录都写入到 binlog 中。

在这里插入图片描述

借助 mysqlbinlog 工具查看 binlog 中的详细内容:

在这里插入图片描述

MySQL 5.7+ 默认使用 row 格式。

Mixed

mixed 格式下,MySQL 会判断 SQL 语句是否可能引起主备不一致,如果有可能,使用 row 格式,否则使用 statement 格式。

持久化

事务执行过程中,先把日志写到内存中的 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中,并清空 binlog cache。

binlog cache 是位于每条线程中的,不同线程/事务之间并发写 binlog cache 时并不会发生冲突,但是最终都写到同一个 binlog 文件。

在这里插入图片描述

  • write 是指把日志写入到 binlog 文件,但是并没有把数据持久化到磁盘,因为数据还缓存在文件系统的 page cache 里,write 的写入速度还是比较快的,因为不涉及磁盘 I/O。
  • fsync 是将数据持久化到磁盘的操作,这里就会涉及磁盘 I/O,所以频繁的 fsync 会导致磁盘的 I/O 升高。

MySQL 提供一个 sync_binlog 参数来控制数据库的 binlog 刷到磁盘上的频率:

  • sync_binlog = 0 的时候,表示每次提交事务都只 write,不 fsync,后续交由操作系统决定何时将数据持久化到磁盘;
  • sync_binlog = 1 的时候,表示每次提交事务都会 write,然后马上执行 fsync;
  • sync_binlog = N 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。

系统默认的设置是 sync_binlog = 0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦主机发生异常重启,还没持久化到磁盘的数据就会丢失。

而当 sync_binlog 设置为 1 的时候,是最安全但是性能损耗最大的设置。因为当设置为 1 的时候,即使主机发生异常重启,最多丢失一个事务的 binlog,而已经持久化到磁盘的数据就不会有影响,不过就是对写入性能影响太大。

MySQL 的双一配置指的是 innodb_flush_log_at_trx_commit 和 sync_binlog 都设置为一,即每次事务提交,redo log 和 binlog 都会刷盘。

redo log 和 binlog 的不同:

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

为什么 binlog cache 是每个线程自己维护的,而 redo log buffer 是全局共用的?

因为 binlog 是不能被打断的,一个事务的 binlog 必须连续写,因此要整个事务完成后再一起写到文件里。而 redo log 不需要连续写。

LSN

Log Sequence Number,日志的逻辑序列号。表空间中的数据页、缓存页、内存中的 rodo log、磁盘中的 redo log 以及 checkponit 都有 LSN 标记。

LSN 的值会随着日志的写入而逐渐增大。新的日志 LSN 等于旧的 LSN 加上新增日志的大小。

LSN 可以用于判断脏页:如果数据页面的 LSN 的值大于 Checkpoint 的 LSN 值,说明这个数据页面有新的更新,即为脏页。

LSN 可以用于崩溃恢复:从 last checkpoint 对应的 LSN 开始重放 redo log。

两阶段提交

2PC,two-phase commit protocol。

事务提交后,redo log 和 binlog 都要持久化到磁盘,但是这两个是独立的逻辑,可能出现半成功的状态,这样就造成两份日志之间的逻辑不一致。

  • 如果在将 redo log 刷入到磁盘之后, MySQL 突然宕机了,而 binlog 还没有来得及写入。MySQL 重启后,通过 redo log 能将 Buffer Pool 中的相应数据恢复到新值,但是 binlog 里面没有记录这条更新语句,在主从架构中,binlog 会被复制到从库,由于 binlog 丢失了这条更新语句,从库的数据是旧值;
  • 如果在将 binlog 刷入到磁盘之后, MySQL 突然宕机了,而 redo log 还没有来得及写入。由于 redo log 还没写,崩溃恢复以后这个事务无效,所以数据还是旧值;而 binlog 里面记录了这条更新语句,数据是新值;

在持久化 redo log 和 binlog 这两份日志的时候,如果出现半成功的状态,就会造成主从环境的数据不一致性。因为 redo log 影响主库的数据,binlog 影响从库的数据,所以 redo log 和 binlog 必须保持一致才能保证主从数据一致。

MySQL 为了避免出现两份日志之间的逻辑不一致的问题,使用了「两阶段提交」来解决,两阶段提交其实是分布式事务一致性协议,它可以保证多个逻辑操作要不全部成功,要不全部失败,不会出现半成功的状态。

当客户端执行 commit 语句或者在自动提交的情况下,MySQL 内部开启一个 XA 事务,分两阶段来完成 XA 事务的提交,分别是准备阶段和提交阶段。

  • prepare 阶段:将 XID(内部 XA 事务的 ID) 写入到 redo log,同时将 redo log 对应的事务状态设置为 prepare,然后将 redo log 持久化到磁盘(innodb_flush_log_at_trx_commit = 1 的作用);
  • commit 阶段:把 XID 写入到 binlog,然后将 binlog 持久化到磁盘(sync_binlog = 1 的作用),接着调用引擎的提交事务接口,将 redo log 状态设置为 commit,此时该状态并不需要持久化到磁盘,只需要 write 到文件系统的 page cache 中就够了,因为只要 binlog 写磁盘成功,就算 redo log 的状态还是 prepare 也没有关系,一样会被认为事务已经执行成功;

在这里插入图片描述

不管是时刻 A(redo log 已经写入磁盘, binlog 还没写入磁盘),还是时刻 B (redo log 和 binlog 都已经写入磁盘,还没写入 commit 标识)崩溃,此时的 redo log 都处于 prepare 状态

在 MySQL 重启后会按顺序扫描 redo log 文件,碰到处于 prepare 状态的 redo log,就拿着 redo log 中的 XID 去 binlog 查看是否存在此 XID:

  • 如果 binlog 中没有当前内部 XA 事务的 XID,说明 redolog 完成刷盘,但是 binlog 还没有刷盘,则回滚事务。对应时刻 A 崩溃恢复的情况。
  • 如果 binlog 中有当前内部 XA 事务的 XID,说明 redolog 和 binlog 都已经完成了刷盘,则提交事务。对应时刻 B 崩溃恢复的情况。

可以看到,对于处于 prepare 阶段的 redo log,即可以提交事务,也可以回滚事务,这取决于是否能在 binlog 中查找到与 redo log 相同的 XID,如果有就提交事务,如果没有就回滚事务。这样就可以保证 redo log 和 binlog 这两份日志的一致性了。

两阶段提交是以 binlog 写成功为事务提交成功的标识。

事务没提交的时候,redo log 也是可能被持久化到磁盘。但是 binlog 必须在事务提交之后,才可以持久化到磁盘。

组提交

两阶段提交虽然保证了两个日志文件的数据一致性,但是性能很差,主要有两个方面的影响:

  • 磁盘 I/O 次数高:对于“双1”配置,每个事务提交都会进行两次 fsync(刷盘),一次是 redo log 刷盘,另一次是 binlog 刷盘。
  • 锁竞争激烈:两阶段提交虽然能够保证「单事务」两个日志的内容一致,但在「多事务」的情况下,却不能保证两者的提交顺序一致,因此,在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性,从而保证多事务的情况下,两个日志的提交顺序一致。

MySQL 引入了 binlog 组提交(group commit)机制,当有多个事务提交的时候,会将多个 binlog 刷盘操作合并成一个,从而减少磁盘 I/O 的次数。

MySQL 5.7 开始有 redo log 组提交。

引入了组提交机制后,prepare 阶段不变,只针对 commit 阶段,将 commit 阶段拆分为三个过程:

  • flush 阶段:多个事务按进入的顺序将 binlog 从 cache 写入文件(不刷盘);
  • sync 阶段:对 binlog 文件做 fsync 操作(多个事务的 binlog 合并一次刷盘);
  • commit 阶段:各个事务按顺序做 InnoDB commit 操作;

上面的每个阶段都有一个队列,每个阶段有锁进行保护,因此保证了事务写入的顺序,第一个进入队列的事务会成为 leader,领导所在队列的所有事务,全权负责整队的操作,完成后通知队内其他事务操作结束。

同一时刻只允许一组事务提交。

崩溃恢复

MySQL 崩溃恢复过程的核心工作有两点:

  • 对于 MySQL 崩溃之前还没有刷新到磁盘的数据页(脏页),用 redo log 把这些数据页恢复到 MySQL 崩溃之前那一刻的状态。

    在这之前,需要用两次写缓冲区中的页把损坏的数据页修复为正常状态。

  • 清理、提交、回滚还没有完成的事务:

    • 对于已完成两阶段提交的 prepare、commit 2 个阶段的事务,做收尾工作;
    • 对于活跃状态的事务,直接回滚;
    • 对于 prepare 状态的事务,如果事务 XID 已写入 binlog 日志文件,提交事务,否则回滚事务;

double write

如果崩溃发生在写数据页的途中,那 redo log 也无法恢复数据,需要依靠 double write 技术恢复数据页。

InnoDB 脏页刷盘前,都会先把脏页写入内存缓冲区,再写入 dblwr 文件,成功之后才会把脏页刷盘。

如果脏页写入内存缓冲区和 dblwr 文件的过程中,MySQL 崩溃了,表空间中对应的数据页还是完整的,下次启动时,不需要用两次写页面修复这个数据页。

如果在脏页刷盘时,MySQL 崩溃了,表空间对应的数据页损坏了,下次启动时,需要用两次写页面修复这个数据页。

double write 也需要写入磁盘,那为什么不直接把 buffer pool 中的数据页刷盘呢?

因为 double write 是顺序写,而 buffer pool 中的数据页是随机写。虽然 double write 会造成部分额外的性能开销,但是能够保证异常恢复。

最后

本文介绍了 MySQL 日志相关的内容,MySQL 中最重要的日志有三个:undo log、redo log 和 binlog。

undo log 主要用于事务回滚和 MVCC,每次修改数据时都会生成一条 undo log,需要回滚时,只需要重放 undo log。

redo log 主要用于持久化和故障恢复,每个写动作都会生成一条 redo log(包括写 undo log 和 binlog),数据和 undo log 的持久化都是通过 redo log 实现的,另外,还可以通过重新执行 redo log 来实现故障恢复。

binlog 主要用于数据备份和主从复制,通过执行 binlog 可以恢复数据。

下一节将介绍 MySQL 内存和磁盘管理部分。

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

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

相关文章

MATLAB程序在设备端部署实例

背景介绍 MATLAB广泛应用于物理系统建模、测量测试、系统控制以及深度学习等,在工程实践中具有非常重要的地位,具体如图1所示。调研发现,科研人员能够编写各种matlab代码,通过建模仿真来更好的认识世界。近年来,随着物…

《LeetCode》—— 摆动序列

今天,我们要讲解的是 “摆动序列” 这道题目。对于这道题目,我们可以从贪心的思想去解决,也可以使用动态规划的方法。接下来,我通过这两种方法的讲解让你轻松拿捏它! 目录 (一)贪心算法 1、上下…

跑在笔记本里的大语言模型 - GPT4All

何为GPT4All GPT4All 官网给自己的定义是:一款免费使用、本地运行、隐私感知的聊天机器人,无需GPU或互联网。 从官网可以得知其主要特点是: 本地运行(可包装成自主知识产权🐶)无需GPU(穷人适配…

sort、uniq、tr、cut的使用

管理文件内容的使用 一、sort命令二、uniq命令三、tr命令四、cut命令 一、sort命令 sort命令是以行为单位对文件内容进行排序,也可以根据不同的数据类型来排序,比较原则是从首字符向后,依次按ASCII码进行比较,最后将他们按升序输…

Linux:rpm查询安装 yum安装

环境: 需要插入安装镜像 镜像内有所需的安装库 我这里使用的虚拟机直接连接光盘 连接的光盘挂载在/dev/cdrom 由于我们无法直接进入,所以选择把/dev/cdrom挂载到别的地方即可 mount /dev/cdrom /123 将/dev/cdrom 挂载到 /123 目录下 Packages下就是…

C++笔记—— 第十七篇 智能指针 C++11来了(下)

目录 1. 为什么需要智能指针 2. 内存泄漏 2.1 什么是内存泄漏,内存泄漏的危害 2.2 内存泄漏分类 2.3如何避免内存泄漏 3.智能指针的使用及原理 3.1 RAII 3.2 智能指针的原理 3.3 std::auto_ptr 3.4 std::unique_ptr 3.5 std::shared_ptr shared_ptr的线…

JVM性能调优

一、JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从JVM启动参…

【牛客刷题专栏】0x28:JZ30 包含min函数的栈(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转),它登陆后会保存刷题记录进度,重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏:个人CSDN牛客刷题专栏。 题目来自:牛客/题库 / 在线编程 / 剑指offer: 目录 前言问…

【神经网络】tensorflow实验9--分类问题

1. 实验目的 ①掌握逻辑回归的基本原理,实现分类器,完成多分类任务; ②掌握逻辑回归中的平方损失函数、交叉熵损失函数以及平均交叉熵损失函数。 2. 实验内容 ①能够使用TensorFlow计算Sigmoid函数、准确率、交叉熵损失函数等&#xff0c…

(浙大陈越版)数据结构 第二章 线性结构 2.4 多项式的加法和乘法运算实现

目录 2.4.1多项式的加法运算实现 如何设计一个函数分别求两个一元多项式的和? 算法思路:两个指针p1,p2分别指向两个多项式的第一个结点(最高项)并循环 循环: 2.4.2 多项式的乘积 1.多项式的表示 2.程…

IPsec VPN IKE方式协商密钥

实验拓扑 要求pc1与pc2两个网络访问走ipsec隧道互访。 前言: ipsecs 隧道两端的acl规则定义的协议类型要一致,如果一端是ip协议,另一端也必须是ip协议 配置acl的原因是:1,通过acl(permit)指定需…

Metalama released Crack

Metalama released Crack Metalama是一个面向C#的元编程框架。它可以帮助您提高代码质量和生产力。使用Metalama,您可以通过在编译过程中动态生成样板文件来减少样板文件。您的源代码仍然非常清晰。根据体系结构、模式和约定实时验证代码。无需等待代码评审。通过定…

React从入门到实战 - React初体验

文章目录 特点相关JS库步骤准备步骤操作步骤 关于虚拟DOMJSX语法规则函数式组件常见的几种错误正确写法 类式组件 特点 采用组件化模式,声明式编程,提高开发效率及组件复用率在React Native 中使用React语法进行移动端开发使用虚拟DOM优秀的Diffing算法…

Java8 map.getOrDefault()你真的了解吗

大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。 map.getOrDefault()方法 在Java编程中,Map是一种非常常用的数据结构。Map通常用于存储键值对,其中每个键映射到一个值。当我们尝试访问一个不…

文件一直处于修改状态 git checkout 无法还原的问题解决方法

问题描述 最近在 RT-Thread 时,使用 Git 回退版本验证问题,后来 git pull 拉取最新代码后,发现里面有几个文件,一直为【修改】状态,并且无法还原,git checkout xxx git reset --hard 都用了,依旧…

基于AT89C51单片机的温度控制系统报警器

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87771724?spm1001.2014.3001.5503 源码获取 单片机读取温度传感器当前的温度值并在LCD液晶显示屏上的第一行显示当前的温度值,单片机读取按键状态并通过…

Flask框架之异常处理、请求钩子、上下文的使用

Flask框架之异常处理、请求钩子、上下文的使用 异常处理捕获指定异常状态码捕获指定异常类型抛出HTTP Exception 请求钩子概述基本使用 请求上下文概述应用上下文current_app对象g对象 请求上下文request对象session对象 异常处理 捕获指定异常状态码 可以使用app.errorhandle…

Github的使用

1.基本概念: 仓库(Repository):仓库用来存放项目代码,每个项目对应一个仓库,多个开源项目则有多个仓库 收藏(Star):收藏项目,方便下次查看 复制克隆项目:(Fork&#x…

JVM类加载、类变量初始化顺序

题目 先来看一个题目,以下程序的输出结果是什么 运行结果 关于类加载机制 关于JVM的类加载 《深入理解Java虚拟机》中关于类加载是这样说的: Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化&#x…

【SLAM学习】基于Pangolin绘制运动轨迹

Pangolin是一个轻量级的跨平台视图控制库,主要用于可视化、交互和调试三维数据。该库提供了一系列图形界面工具,包括窗口、OpenGL渲染器、3D相机、图像显示等,可以方便地进行三维数据可视化和交互。 Pangolin库的主要特点如下: 轻…