mysql中 redo日志(上)

大家好。我们知道InnoDB 存储引擎是以页为单位来管理存储空间的,我们进行的增删改查操作其实本质上都是在访问页面。而在真正访问页面之前,需要把在磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。那么我们思考一个问题:如果我们只在内存的Buffer Pool 中修改了页面,在事务提交后突然发生了某个故障,导致内存中的数据都失效了,这个时候已经提交了的事务对数据库中所做的更改也就跟着丢失了。我们如何才能避免这种情况的发生呢?

其实方法很简单:我们只要让已经提交了的事务对数据库中数据所做的修改永久生效,即使后来系统崩溃,在重启后也能把这种修改恢复出来就行。为了实现这个功能,也就是为了满足持久性的要求,mysql会把修改了哪些东西记录下来。在事务提交时,把上述内容刷新到磁盘中,即使之后系统崩溃了,重启之后只要按照上述内容所记录的步骤重新更新一下数据页,该事务对数据库中所做的修改又可以被恢复出来。因为在系统崩溃重启时需要按照上述内容所记录的步骤重新更新数据页,所以上述内容也被称之为重做日志,也就是今天我们要讲的redo日志

一、redo日志格式

redo日志本质上只是记录了一下事务对数据库做了哪些修改。InnoDB针对事务对数据库的不同修改场景定义了多种类型的redo日志,但是绝大部分类型的redo日志都有下边这种通用的结构:
图片
各个部分的详细释义如下:

type: 该条 redo 日志的类型。

space ID: 表空间ID。

page number: 页号。

data: 该条 redo 日志的具体内容。

1. 简单的redo日志类型

众所周知,如果我们没有为某个表显式的定义主键,并且表中也没有定义Unique键,那么InnoDB会自动的为表添加一个称之为row_id的隐藏列作为主键。为这个 row_id 隐藏列赋值 的方式如下:

  1. 服务器会在内存中维护一个全局变量,每当向某个包含隐藏的row_id列的表中插入一条记录时,就会把该变量的值当作新记录的row_id列的值,并且把该变量自增1。

  2. 每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为7的页面中一个称之为Max Row ID的属性处。

  3. 当系统启动时,会将Max Row ID属性加载到内存中,将该值加上256之后赋值给全局变量。

这个Max Row ID 属性占用的存储空间是8个字节,当某个事务向某个包含row_id隐藏列的表插入一条记录,并且为该记录分配的row_id值为256的倍数时,就会向系统表空间页号为7的页面的相应偏移量处写入8个字节的值。但是这个写入实际上是在Buffer Pool 中完成的,所以我们需要为这个页面的修改记录一条redo日志,以便在系统崩溃后能将已经提交的该事务对该页面所做的修改恢复出来。

这种情况下对页面的修改是极其简单的,redo日志中只需要记录一下在某个页面的某个偏移量处修改了几个字节的值,具体被修改的内容是什么就好了,InnoDB把这种极其简单的redo日志称之为物理日志,并且根据在页面中写入数据的多少划分了几种不同的redo日志类型:

MLOG_1BYTE(type字段对应的十进制数字为 1): 表示在页面的某个偏移量处写入1个字节的redo日志类型。

MLOG_2BYTE(type字段对应的十进制数字为 2): 表示在页面的某个偏移量处写入2个字节的redo日志类型。

MLOG_4BYTE(type字段对应的十进制数字为 4): 表示在页面的某个偏移量处写入4个字节的redo日志类型。

MLOG_8BYTE(type字段对应的十进制数字为 8): 表示在页面的某个偏移量处写入8个字节的redo日志类型。

MLOG_WRITE_STRING(type字段对应的十进制数字为 30): 表示在页面的某个偏移量处写入一串数据。

我们上边提到的Max Row ID属性实际占用8个字节的存储空间,所以在修改页面中的该属性时,会记录一条类型 为MLOG_8BYTE的redo日志, MLOG_8BYTE 的redo日志结构如下所示:
图片
其余MLOG_1BYTE、MLOG_2BYTE 、MLOG_4BYTE类型的redo日志结构和MLOG_8BYTE的类似,只不过具体数据中包含对应个字节的数据罢了。MLOG_WRITE_STRING类型的redo日志表示写入一串数据,但是因为不能确定写入的具体数据占用多少字节,所以需要在日志结构中添加一个len字段:
图片

2. 复杂一些的redo日志类型

有时候执行一条语句会修改非常多的页面,包括系统数据页面和用户数据页面。以一条INSERT语句为例,它除了要向B+树的页面中插入数据,也可能更新系统数据Max Row ID的值。对于我们用户来说,平时更关心的是语句对B+树所做更新:

  1. 表中包含多少个索引,一条INSERT 语句就可能更新多少棵B+树。

  2. 针对某一棵B+树来说,既可能更新叶子节点页面,也可能更新内节点页面,也可能创建新的页面(在该记录插入的叶子节点的剩余空间比较少,不足以存放该记录时,会进行页面的分裂,在内节点页面中添加目录 项记录)。

在语句执行过程中,INSERT语句对所有页面的修改都得保存到redo 日志中去。所以每往叶子节点代表的数据页里插入一条记录时,还有其他很多地方会跟着更新,比如:

  1. 可能更新Page Directory中的槽信息。

  2. Page Header 中的各种页面统计信息,比如PAGE_N_DIR_SLOTS表示的槽数量可能会更改, PAGE_HEAP_TOP代表的还未使用的空间最小地址可能会更改,PAGE_N_HEAP代表的本页面中的记录数量可能会更改。

  3. 各种信息都可能会被修改。我们知道在数据页里的记录是按照索引列从小到大的顺序组成一个单向链表的,每插入一条记录,还需要更新上一条记录的记录头信息中的next_record属性来维护这个单向链表。
    画一个简易的示意图就像是这样:在这里插入图片描述

可以看到,把一条记录插入到一个页面时需要更改的地方非常多。这时我们如果使用上边介绍的简单的物理redo日志来记录这些修改时,可以有两种解决方案:

方案一:在每个修改的地方都记录一条redo日志。也就是如上图所示,有多少个加粗的块,就写多少条物理redo日志。但是这样记录redo日志的的时候被修改的地方太多了,可能记录的redo日志占用的空间都比整个页面占用的空间都多了。

方案二:将整个页面的第一个被修改的字节到最后一个修改的字节之间所有的数据当成是一条物理redo日志中的具体数据。 但是从第一个被修改的字节到最后一个修改的字节之间很可能会有许多没有修改过的数据,把这些没有修改的数据也加入到redo日志中也是有些浪费。

为了避免这些所谓的浪费,InnoDB提出了一些新的redo日志类型,比如:

MLOG_REC_INSERT(对应的十进制数字为 9): 表示插入一条非紧凑行格式(Redundant)的记录时的redo日志类型。

MLOG_COMP_REC_INSERT(对应的十进制数字为38): 表示插入一条使用紧凑行格式(Compact、Dynamic、Compressed)的记录时的redo日志类型。

MLOG_COMP_PAGE_CREATE(type 字段对应的十进制数字为58 ): 表示创建一个存储紧凑行格式记录的页面的redo 日志类型。

MLOG_COMP_REC_DELETE(type 字段对应的十进制数字为42 ): 表示删除一条使用紧凑行格式记录的redo日志类型。

MLOG_COMP_LIST_START_DELETE(type 字段对应的十进制数字为 44 ): 表示从某条给定记录开始删除页面中的一系列使用紧凑行格式记录的redo日志类型。

MLOG_COMP_LIST_END_DELETE(type 字段对应的十进制数字为 43): 与MLOG_COMP_LIST_START_DELETE类型的redo日志呼应,表示删除一系列记录直到MLOG_COMP_LIST_END_DELETE类型的redo 日志对应的记录为止。

MLOG_ZIP_PAGE_COMPRESS(type字段对应的十进制数字为51 ): 表示压缩一个数据页的redo日志类 型。

这些类型的redo 日志既包含物理层面的意思,也包含逻辑层面的意思,具体指:

物理层面看: 这些日志都指明了对哪个表空间的哪个页进行了修改。

逻辑层面看: 在系统崩溃重启时,并不能直接根据这些日志里的记载,将页面内的某个偏移量处恢复成某个数据,而是需要调用一些事先准备好的函数,执行完这些函数后才可以将页面恢复成系统崩溃前的样子。

下面我们以类型为MLOG_COMP_REC_INSERT这个代表插入一条使用紧凑行格式的记录时的redo日志为例来理解一下我们上边所说的物理层面和逻辑层面是什么意思。废话少说,直接看一下这个类型为MLOG_COMP_REC_INSERT的redo日志的结构:
在这里插入图片描述

这个类型为MLOG_COMP_REC_INSERT的 redo日志结构有几个地方需要注意:

  1. 在一个数据页里,不论是叶子节点还是非叶子节点,记录都是按照索引列从小到大的顺序排序的。对于二级索引来说,当索引列的值相同时,记录还需要按照主键值进行排序。图中n_uniques的值的含义是在一条记录中,需要几个字段的值才能确保记录的唯一性,这样当插入一条记录时 就可以按照记录的前n_uniques个字段进行排序。对于聚簇索引来说, n_uniques的值为主键的列数,对于其他二级索引来说,该值为索引列数+主键列数。这里需要注意的是,唯一二级索引的值可能为NULL,所以该值仍然为索引列数+主键列数。
  2. field1_len ~ fieldn_len 代表着该记录若干个字段占用存储空间的大小,需要注意的是,这里不管该字段的类型是固定长度大小的还是可变长度大小的,该字段占用的大小始终要写入redo日志中。
  3. offset 代表的是该记录的前一条记录在页面中的地址。因为每向数 据页插入一条记录,都需要修改该页面中维护的记录链表,每条记录的记录头信息中都包含一个称为next_record的属性,所以在插入新记录时,需要修改前一条记录的next_record属性。
  4. 我们知道一条记录其实由额外信息和真实数据这两部分组成,这两个部分的总大小就是一条记录占用存储空间的总大小。通过end_seg_len 的值可以间接的计算出一条记录占用存储空间的总大小,为什么不直接存储 一条记录占用存储空间的总大小呢?这是因为写redo日志是一个非常频繁的操作,InnoDB想方设法想减小redo 日志本身占用的存储空间大小,end_seg_len这个字段就是为了节省 redo 日志存储空间而提出来的。
  5. mismatch_index的值也是为了节省redo日志的大小而设立的。
    很显然这个类型为MLOG_COMP_REC_INSERT的redo日志并没有记录PAGE_N_DIR_SLOTS的值修改为了什么,PAGE_HEAP_TOP的值修改为了什么, PAGE_N_HEAP的值修改了什么等信息,而只是把在本页面中插入一条记录所有必备的要素记了下来,之后系统奔溃重启时,服务器会调用相关向某个页面插入一条记录的那个函数,而redo日志中的那些数据就可以被当成是调用这个函数所需的参数,在调用完该函数后,页面中的 PAGE_N_DIR_SLOTS、 PAGE_HEAP_TOP、 PAGE_N_HEAP等等的值也就都被恢复到系统奔溃前的样子了。这就是所谓的逻辑日志的意思。

二、Mini-Transaction

1. 以组的形式写入redo日志

语句在执行过程中可能修改若干个页面。由于对这些页面的更改都发生在Buffer Pool中,所以在修改完页面之后,需要记录一下相应的redo 日志。在执行语句的过程中产生的redo日志被InnoDB划分成了若干个不可分割的组,比如:

更新Max Row ID属性时产生的redo日志是不可分割的。

向聚簇索引对应B+树的页面中插入一条记录时产生的redo日志是不可分割的。

向某个二级索引对应B+树的页面中插入一条记录时产生的redo日志是不可分割的。

还有其他的一些对页面的访问操作时产生的redo日志是不可分割的。

怎么理解这个不可分割的意思呢?我们以向某个索引对应的B+树插入一条记录为例,在向B+树中插入这条记录之前,需要先定位到这条记录应该被插入到哪个叶子节点代表的数据页中,定位到具体的数据页之后,有两种可能的情况:

情况一:该数据页的剩余的空闲空间充足,足够容纳这一条待插入记录,那么直接把记录插入到这个数据页中,记录一条类型为MLOG_COMP_REC_INSERT的redo日志就好了,我们把这种情况称之为 乐观插入。假如某个索引对应的B+树长这样:
在这里插入图片描述

当我们要插入一条键值为10的记录时,很显然需要被插入到页b中,由于页b现在有足够的空间容纳一条记录,所以直接将该记录插入到页b中就好了,就像这样:
在这里插入图片描述

情况二:该数据页剩余的空闲空间不足,遇到这种情况要进行所谓的页分裂操作,也就是新建一个叶子节点,然后把原先数据页中的一部分记录复制到这个新的数据页中,然后再把记录插入进去,把这个叶子节点插入到叶子节点链表中,最后还要在内节点中添加一条目录项记录指向这个新创建的页面。很显然,这个过程要对多个页面进行修改,也就意味着会产生多条redo日志,我们把这种情况称之为悲观插入。假如某个索引对应的B+树长这样:
在这里插入图片描述

现在我们要插入一条键值为10的记录,很显然需要被插入到页b中,但是从图中也可以看出来,此时页b已经塞满了记录,没有更多的空闲空间来容纳这条新记录了,所以我们需要进行页面的分裂操作,就像这样:
在这里插入图片描述

如果作为内节点的页a的剩余空闲空间也不足以容纳增加一条目录项记录,那需要继续做内节点页a的分裂操作,也就意味着会修改更多的页面,从而产生更多的redo日志。

InnoDB认为向某个索引对应的B+树中插入一条记录的这个过程必须是原子的,不能说插了一半之后就停止了。比方说在悲观插入过程中,新的页面已经分配好了,数据也复制过去了,新的记录也插入到页面中了,可是没有向内节点中插入一条目录项记录,这个插入过程就是不完整的,这样会形成一棵不正确的B+树。而redo日志是为了在系统崩溃重启时恢复崩溃前的状态,如果在悲观插入的过程中只记录了一部分redo日志,那么在系统崩溃重启时会将索引对应的B+树恢复成一种不正确的状态。

所以InnoDB规定在执行这些需要保证原子性的操作时必须以组的形式来记录的redo日志,在进行系统崩溃重启恢复时,针对某个组中的redo日志,要么把全部的日志都恢复掉,要么一条也不恢复。怎么做到的呢?这得分情况讨论:

情况一:有的需要保证原子性的操作会生成多条redo日志,比如向某个索引对应的B+树中进行一次悲观插入就需要生成许多条redo 日志。InnoDB会在该组中的最后一条redo日志后边加上一条特殊类型的redo日志,该类型名称为MLOG_MULTI_REC_END, type字段对应的十进制数字为31,该类型的redo日志结构很简单,只有一个type字段:

在这里插入图片描述

所以某个需要保证原子性的操作产生的一系列redo日志必须要以一个类型为MLOG_MULTI_REC_END 结尾,就像这样:

在这里插入图片描述

这样在系统崩溃重启进行恢复时,只有当解析到类型为MLOG_MULTI_REC_END的redo日志,才认为解析到了一组完整的redo 日志,才会进行恢复。否则的话直接放弃前边解析到的redo日志。
情况二、有的需要保证原子性的操作只生成一条redo日志,比如更新Max Row ID属性的操作就只会生成一条 redo 日志。其实在一条日志后边跟一个类型为MLOG_MULTI_REC_END的redo日志也是可以的,不过InnoDB为了不浪费一个比特位,这种情况的示意图如下:
在这里插入图片描述

如果type 字段的第一个比特位为1,代表该需要保证原子性的操作只产生了单一的一条redo日志,否则 表示该需要保证原子性的操作产生了一系列的redo日志。

2. Mini-Transaction的概念

MySQL把对底层页面中的一次原子访问的过程称之为一个Mini-Transaction,简称mtr。

比如上边所说的修改一次Max Row ID的值算是一个Mini-Transaction,向某个索引对应的B+树中插入一条记录的过程也算是一个Mini-Transaction。通过上边的叙述我们也知道,一个所谓的mtr可以包含一组redo日志,在进行崩溃恢复时这一组redo 日志作为一个不可分割的整体。一个事务可以包含若干条语句,每一条语句其实是由若干个mtr组成,每一个mtr又可以包含若干条redo日志,画个图表示它们的关系就是这样:
图片

三、redo日志的写入过程

1. redo log block

InnoDB为了更好的进行系统崩溃恢复,把通过mtr生成的redo日志都放在了大小为512字节的页中。为了和我们前边提到的表空间中的页做区别,我们这里把用来存储redo日志的页称为block。一个redo log block 的示意图如下:
在这里插入图片描述

真正的redo日志都是存储到占用496 字节大小的log block body 中,图中的 log block header 和 log block trailer 存储的是一些管理信息。我们来看看这些所谓的管理信息:
图片

其中log block header 的几个属性的意思分别如下:

LOG_BLOCK_HDR_NO: 每一个block都有一个大于0的唯一标号,本属性就表示该标号值。

LOG_BLOCK_HDR_DATA_LEN: 表示block中已经使用了多少字节,初始值为12(因为log block body从第12个字节处开始)。随着往block中写入的redo日志越来越多,本属性值也跟着增长。如果log block body已经被全部写满,那么本属性的值被设置为512。

LOG_BLOCK_FIRST_REC_GROUP: 一条redo日志也可以称之为一条redo日志记录(redo log record), 一个mtr会生产多条redo日志记录,这些redo日志记录被称之为一个redo日志记录组(redo log record group )。LOG_BLOCK_FIRST_REC_GROUP就代表该block中第一个 mtr生成的redo日志记录组的偏移量(其实也就是这个block里第一个mtr 生成的第一条redo日志的偏移量)。

LOG_BLOCK_CHECKPOINT_NO: 表示所谓的checkpoint的序号。

log block trailer中属性的意思如下:

LOG_BLOCK_CHECKSUM: 表示block的校验值,用于正确性校验。

2. redo日志缓冲区

我们知道,InnoDB为了解决磁盘速度过慢的问题而引入了Buffer Pool 。同理,写入redo日志时也不能直接直接写到磁盘上,实际上在服务器启动时就向操作系统申请了一大片称之为redo log buffer的连续内存空间,我们也可以简称为log buffer。这片内存空间被划分成若干个连续的redo log block,我们可以通过启动参数innodb_log_buffer_size来指定log buffer的大小。log buffer的结构示意图如下:
图片

3. redo日志写入log buffer

向log buffer中写入redo日志的过程是顺序的,也就是先往前边的block中写,当该block的空闲空间用完之后再往下一个block中写。当我们想往log buffer中写入redo日志时,第一个遇到的问题就是应该写在哪个 block 的哪个偏移量处,所以InnoDB提供了一个称之为buf_free的全局变量,该变量指明后续写入的redo日志应该写入到log buffer 中的哪个位置,如图所示:

图片

我们前边说过一个mtr执行过程中可能产生若干条redo日志,这些redo日志是一个不可分割的组,所以其实并不是每生成一条redo日志,就将其插入到log buffer中,而是每个mtr运行过程中产生的日志先暂时存到 一个地方,当该mtr 结束的时候,将过程中产生的一组redo日志再全部复制到log buffer中。

我们现在假设有两个名为T1、T2的事务,每个事务都包含2个mtr,我们给这几个mtr命名一下:事务T1的两个mtr 分别称为mtr_T1_1和 mtr_T1_2 。事务T2的两个mtr分别称为mtr_T2_1和mtr_T2_2。每个mtr都会产生一组redo日志,用示意图来描述一下这些mtr产生的日志情况:
图片

不同的事务可能是并发执行的,所以T1、T2之间的mtr可能是交替执行的。每当一个mtr执行完成时,伴随该mtr生成的一组redo日志就需要被复制到log buffer中,也就是说不同事务的mtr可能是交替写入log buffer 的,我们画个示意图(为了美观,我们把一个mtr 中产生的所有的redo 日志当作一个整体来画):
图片

从示意图中我们可以看出来,不同的mtr产生的一组redo日志占用的存储空间可能不一样,有的mtr产生的redo日志量很少,比如mtr_t1_1 、 mtr_t2_1就被放到同一个block中存储,有的mtr产生的redo日志量非常 大,比如mtr_t1_2产生的redo日志甚至占用了3个block来存储。

好了,今天就先讲到这里,今天我们讲了什么是redo日志、redo日志的格式以及redo日志的写入过程,明天我们再来讲一下redo日志的其他内容。

大家有什么想法欢迎留言讨论。也希望大家能给作者点个关注,谢谢大家!最后依旧是请各位老板有钱的捧个人场,没钱的也捧个人场,谢谢各位老板!

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

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

相关文章

vue2中使用tinymce

vue2中使用tinymce的记录 本篇文章主要实现的功能: (1)【查看】时禁用编辑 (2)【编辑】时某些内容是不可编辑的 (3)【内容】前端拼接编辑器模板 (4)【内容】编辑器模板中…

【漏洞复现】锐捷校园网自助服务系统 login_judge.jsf 任意文件读取漏洞(XVE-2024-2116)

0x01 产品简介 锐捷校园网自助服务系统是锐捷网络推出的一款面向学校和校园网络管理的解决方案。该系统旨在提供便捷的网络自助服务,使学生、教职员工和网络管理员能够更好地管理和利用校园网络资源。 0x02 漏洞概述 校园网自助服务系统/selfservice/selfservice…

Java核心: 为图片生成水印

今天干了一件特别不务正业的事,做了一个小程序用来给图片添加水印。事情的起因是需要将自己的身份证照片分享给别人,手边并没有一个趁手的工具来生成图片水印。很多APP提供了水印的功能,但会把我的图片上传到他们的服务器,身份证太…

台式机安装Windows 11和Ubuntu 22双系统引导问题

一、基本情况 1.1、硬件情况 电脑有2个NVMe固态硬盘,1个SATA固态硬盘,1个机械硬盘。其中一个NVMe固态硬盘是Windows系统盘,另一个NVMe固态为Windows软件和文件盘,SATA固态硬盘为Ubuntu专用,机械硬盘为数据备份盘。 …

Find My电动螺丝刀|苹果Find My技术与螺丝刀结合,智能防丢,全球定位

电动螺丝刀,别名电批、电动起子,是用于拧紧和旋松螺钉用的电动工具。它不仅提高了工作效率,还大大减轻了工作者的体力负担。在装配线等生产环境中,电动螺丝刀已经成为了不可或缺的工具。电动螺丝刀的批头还具备接地防静电功能&…

Leetcode:四数之和

题目链接:18. 四数之和 - 力扣(LeetCode) 普通版本(排序 双指针) 主旨:类似于三数之和的解法,但需要多加一些限制,同时为了防止多个数组元素的相加之和出现整型溢出问题还要将整型…

IDEA 2022

介绍 【尚硅谷IDEA安装idea实战教程(百万播放,新版来袭)】 jetbrains 中文官网 IDEA 官网 IDEA 从 IDEA 2022.1 版本开始支持 JDK 17,也就是说如果想要使用 JDK 17,那么就要下载 IDEA 2022.1 或之后的版本。 公司…

《TCP/IP网络编程》(第十三章)多种I/O函数(2)

使用readv和writev函数可以提高数据通信的效率,它们的功能可以概括为**“对数据进行整合传输及发送”**。 即使用writev函数可以将分散在多个缓冲中的数据一并发送,使用readv函数可以由多个缓冲分别接受,所以适当使用他们可以减少I/O函数的调…

Refused to load the stylesheet问题解决方案

今天项目部署的过程中遇到一个安全策略问题的报错&#xff0c;大概意思就是处于安全考虑&#xff0c;不允许src外链其他不安全的静态文件 解决这种问题的一个思路大概就是找到index.html文件先看下是否存在 <meta http-equiv"Content-Security-Policy" content&…

用PlayCanvas打造一个令人惊叹的3D图在线展示

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 PlayCanvas实例化渲染&#xff1a;大规模渲染优化 应用场景 在游戏开发中&#xff0c;经常需要渲染大量相同或相似模型。传统方法需要为每个模型创建单独的渲染对象&#xff0c;这会消耗大量内存和GPU资源。实…

问你为什么选择Kafka,你会怎么回答?

可靠的含义在百度百科的解释是&#xff1a;可以信赖、可以相信、可靠的朋友。那Kafka究竟是不是一个可靠的朋友呢&#xff1f;既然全世界绝大部分高可用系统都有Kafka的支持&#xff0c;Kafka必定有其过人之处&#xff0c;跟着我来分析分析。 另外多提一嘴Kafka在GitHub目前已…

【AIGC X UML 落地】通过多智能体实现自然语言绘制UML图

前天写了篇博文讲到用PlantUML来绘制C类图和流程图。后台有读者留言&#xff0c;问这步能否自动化生成&#xff0c;不想学习 PlantUML 语法。 我想了下&#xff0c;发现这事可行&#xff0c;确实可以做到通过自然语言的描述就能实现 UML图的绘制&#xff0c;昨天晚上加了个班到…

安装TPMmanager

sudo apt-get install qt4-qmake sudo apt-get install libqt4-dev下载TPMManager&#xff0c;解压之后拖入Ubuntu&#xff0c;进入目录 https://gitcode.com/Rohde-Schwarz/TPMManager/overview?utm_sourcecsdn_github_accelerator&isLogin1 cd tpmmanager-master qmake…

快速排序(Quick Sort)(C语言) 超详细解析!!!

生活的本质是什么呢? 无非就是你要什么就不给你什么. 而生活的智慧是什么呢? 是给你什么就用好什么. ---马斯克 索引 一. 前言二. 快速排序的概念三. 快速排序的实现1. hoare2. 挖坑法3. 前后指针法 总结 正文开始 一. 前言 接上文, 前面我们了解了插入排序, 与优化版本希尔…

Vulnhub-DC-2

靶机IP:192.168.20.135 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) kaliIP:192.168.20.128 扫描靶机端口及服务版本 发现开放了80和7744端口 并且是wordpress建站 dirsearch扫描目录 访问前端界面&#xff0c;发现存在重定向 在hosts文件中增加192.168.2…

【UML用户指南】-09-对基本结构建模-类图

目录 1、概述 2、引入 3、过程 4、常用建模技术 4.1、对简单协作建模 4.2、对逻辑数据库模式建模 4.3、正向工程 1、概述 类图是面向对象系统建模中最常见的图。 类图显示一组类、接口、协作以及它们之间的关系 类图用于对系统静态设计视图建模。其大多数涉及到对系统的…

这个世界,对于心态好的人,就是个大游乐场,越刺激越好玩。对于胆小鬼,那就是地狱,随时随地都会受伤

心态决定你的世界&#xff1a;游乐场还是地狱 在这个充满变数的世界里&#xff0c;我们的心态决定了我们看待世界的方式。对于心态积极的人来说&#xff0c;世界就像一个巨大的游乐场&#xff0c;每一个挑战都是一个新的游戏&#xff0c;每一个刺激都是乐趣的一部分。而对于那…

纷享销客安全体系: 组织及人员安全

组织及人员安全是纷享销客安全战略中的重要组成部分。 我们致力于确保组织内部和员工的安全&#xff0c;并采取一系列措施来预防和应对安全威胁。我们将持续改进和更新安全措施&#xff0c;以适应不断变化的威胁环境&#xff0c;并确保组织和员工的安全意识和培训得到充分关注…

鹧鸪云设计系统:太阳能光伏发电设计图纸绘制全攻略

随着全球对可持续能源的需求不断增加&#xff0c;越来越多的人开始关注太阳能发电技术。对于初学者来说&#xff0c;掌握一套有效的太阳能光伏发电设计图纸至关重要。本为了实现这一目标&#xff0c;鹧鸪云设计系统的出现为初学者的电站图纸绘制降低了难度。 接下来&#xff0c…

微信小程序uniapp的父子之间的通信传递

1.父传递给子信息 my-test是子组件 demo是父组件 这是定义在父组件中的的info信息 要将这个传递给子组件 子组件在properties 中接收父组件传递来的数据 msg type 是类型 value是默认值&#xff0c;当父组件没有传递数据时&#xff0c;就会默认使用value的数据 子组件…