mysql面试(四)

前言

本章节有些长,主要的篇幅是介绍缓存页的算法,如何快速的定位哪些是没有用过的,哪些是用过的,哪些是要淘汰掉的。
建议可以阅读一下这里面LRU算法相关的内容,和很多组件里面基本原理都是想通的,比如redis的淘汰算法等。

缓存页Buffer Pool

为什么需要缓存

在上面的时候,我们讲过,mysql中的真实数据确实都是存储在磁盘文件上的,这就是在物理层面的存储,哪怕服务器宕机了,也不会影响这些磁盘上被写入的数据。
但是这里存在一个问题,就是在我们读写的时候,如果直接读写磁盘上的数据,速度会特别慢,通常以每秒几十至几百兆字节。因为这是磁盘在物理层面读取的限制,比如机械硬盘读取的时候,是移动机械臂,并且将磁盘转动到指定的扇区才能读取或者写入数据。固态硬盘虽然是通过电子芯片方式来存储数据,读写速度比机械硬盘快的多,但是获取数据也是要通过固定的电子路径来处理。所以磁盘中的数据注定了不能做到快速读写。
但是我们在线上的时候获取数据都是纳秒级的,这时候就需要用到缓存了,也就是数据直接从内存中读取。要注意的是,这个缓存并不是我们自己升级电脑时候搞的那个内存条。而是在处理器(CPU)中集成的缓存区。这些展开讲就没个头了,这里只是简单提一下。

什么是缓存页

刚才说了,当我们读写磁盘数据的时候,其实都是在缓存中修改的。那么在缓存中肯定是要给mysql提前划分出来一片区域来存储这些缓存数据,而这个区域就叫做缓存池Buffer Pool。
这个缓存池中存储数据的时候,为了我们读写的时候方便,也会在其中划分出来一片片的小内存区域。而这个小小的内存分区就是缓存页。
这个缓存页是默认的大小 16KB,而缓存池的默认大小是128M。如果服务器的内存足够大,完全可以给Buffer Pool分配的大一些。比如服务为16核32G的机器,就可以分配2G的配置是完全没问题的。
缓存页16K这个大小也是有讲究的,他是和mysql磁盘存储数据也大小完全一致的。
我们都知道,mysql数据库核心的存储模型就是表+字段+行的概念,也就是说,我们知道数据库中的有一个个的表,每个表有一行行个的数据。每行数据都有自己的字段值。
但是mysql对这些数据抽象出来了一个数据页的概念,把很多行的数据放在了一个数据页中。那么我们查询的时候,就是先确定要查询的数据存储在哪个数据页中,然后再到对应的数据页获取数据。这个流程会涉及到索引,我们后面再详细说。
需要注意的一点是,每个缓存页都有一些描述数据,大概占缓存页的5%左右,也就是800个字节吧,所以当我们设置Buffer Pool 128M的时候,实际上的大小会超出一些。
如图:
在这里插入图片描述

如何初始化Buffer Pool

只要在数据库启动的时候,就会按照我们设置的Buffer Pool大小来向操作系统进行申请,划分出来一块相应的区域。
当这块内容申请完毕之后,数据库就会按照默认的缓存页每个16K的大小以及对应的800个字节描述数据的大小在Buffer Pool中划分出来一个个的缓存页和一个对应的描述数据。
当划分完成之后,就是我们上面的那张图的样式了。当然,这时候所有的缓存页中的数据都是空的,等到有请求要对数据进行增删改查的时候,才会把对应的数据从磁盘文件的数据页中提出来放入缓存页中。

如何判断哪些缓存页是空的

当我们想要将数据从磁盘的数据页中拿出来,放入缓存页的时候,不单单是简单的放入缓存页。还要先确定缓存页是否为空。 就好像把大象放进冰箱的时候,也要先确定里面是不是有个长颈鹿,对吧。
那如果按照一个简单的方式,想要存入这个缓存页,先看一眼有没有数据,没有的话放入,有的话去看下一个。这样的话缓存页少的话当然没有问题,但是存储数据肯定不会是简单一点点的数据而已,就按照最简单的128M,16k一个缓存,换算下来,也得好几千个。那能判断几千次吗? 肯定不能这样搞。
所以这里就有一个free链表的概念,是一个双向链表的结构。每一个节点都是缓存的描述数据储存地址。并且这个链表中的描述数据都是指向空闲的数据页。
我们可以想象一下,当初始化的时候,所有的数据页都是空的,那么所有的描述数据都会存放在这个free链表中。如图所示:
在这里插入图片描述

free链表

大家可以看到,上面有一个由多个节点组成的链表数据,只要数据页是空闲的,那么他对应的描述数据都会加入这个链表中,每个节点都会同时指向自己的前后两个节点。
还有一点就是free链表有一个基础节点,他会引用链表的头节点和尾节点,并且里面还存储了当前有链表中包含多少描述数据节点,也就是有多少个缓存页。
那么free链表是怎么存储的呢,难道也要开辟出来一个单独的数据块来存储吗,那这样一搞,不就会导致描述数据冗余存储了? 或者是再多出来一个用来描述 描述数据 的数据结构吗? 玩套娃来了这是
当然不会这样搞,其实这个free链表是一个抽象的概念,他的本身就是这些描述数据。每一个描述数据都会有两个指针,一个是free_pre,一个是free_next,用来指向上一个free链表节点,和下一个free链表节点。
这样一来就像两条绳子一样,把所有的空闲描述数据给串联起来,构成一个free链表。
对于这个链表而言,只有一个基础节点不是描述数据。存放的就是链表头尾节点的地址,还有free链表中有多少个节点。
为什么要使用双向链表,按照当前逻辑,单向链表也是可以实现的。
因为只有双向链表才可以获取到上一个节点,否则我们直接申请最后面节点的话,是无法直接修改上一个节点的指针的。

将数据读取到缓存页中

既然现在已经知道哪些缓存页是空的了,那么就可以直接从磁盘中拿数据,然后从free链表中拿一个节点的描述数据,获取到对应缓存页的地址。
再把这些数据写入到缓存页中去了,同时将数据的表空间之类的信息写入到描述数据中。
最后要做的就是将这个已经使用的描述数据从free链表中移除掉
比如这里有三个节点,每个节点都指向了前后节点,要移除尾部节点的时候,只需要将第二个节点的naxt指向改为null,链表中就不存在第三个节点了。
在这里插入图片描述

如何知道数据是否已经被缓存

现在,已经可以判断哪些缓存页为空,可以将数据存进去了。但是还有一个问题要解决,就是缓存这个数据的时候,怎么知道这个数据已经被缓存过了呢? 肯定也不能是一个个描述数据去看的。
所以这时候还有另一个数据结构,一个哈希表数结构
每当我们在缓存页中存入数据,就会通过“表空间号+数据页号”作为一个key,将缓存页的地址作为value,将其存入哈希表中。
存疑
那么,当想要缓存数据的时候,先通过“表空间号+数据页号”作为一个key去哈希表中查询一下看数据是否存在,如果存在的话肯定就是已经被缓存了,不需要重复缓存。

在这里插入图片描述

脏页和flush链表

根据上面我们说过的一个更新链路来看,肯定是要先更新缓存,然后InnoDB会去定时把数据刷到磁盘上。而这些先在缓存页中修改的,并未刷到磁盘中的数据,就是属于脏页。
最终这些脏页肯定都是要刷到磁盘中的,但是肯定不会所有的缓存页都需要刷回去啊。这时候就需要有个机制来记录哪些数据页是需要回刷的。
于是flush链表就产生了,他的本质和free链表类似,也是由被修改过的数据页描述块指向前后两个节点,形成一个双线链表。
凡是被修改过的数据页,都会被加入这个flush链表中。如图:在这里插入图片描述

LRU淘汰算法

现在已经解决了空页问题,重复缓存问题,数据回刷问题。
但是还有一个问题,因为Buffer Pool的空间肯定是比磁盘中的空间小的,肯定会有占满的时候,所以Buffer Pool中缓存的数据一定是部分数据。当访问到Buffer Pool中不存在的数据,要去磁盘中找,找到之后也是要放在缓存中的。这个时候,free链表中已经没有空余数据页了,该怎么去删除缓存中现有的数据页呢?
如果随便删的话,删到热点数据怎么办。就是那种本来频繁查询使用的数据,如果从缓存中移除的话肯定还是会很快再次被更新到缓存中。那这多次去磁盘中查询,不又浪费了资源么。我们肯定是要提高缓存命中率的。
所以需要有一个淘汰机制来确定哪些数据页是被使用次数最少的。淘汰掉这些不频繁使用的数据页才是最好的方法。
此时引入了一个新的LRU链表,所谓的LRU就是Least Recetly Used,最近最少使用的意思。
通过这个LRU链表,我们可以确定有哪些缓存页是最近最少被会用的。那么当缓存页需要腾出来一个,用来放入新数据的时候,不就可以直接拿着用了么。PS:插一句,Redis淘汰机制也有用这个类似算法。
先简单了解一下这个LRU链表的工作原理。
大致意思是,每当从磁盘中加载一个数据页的时候,就把这个缓存页的描述数据放到LRU链表的头部来。这样一来所有的缓存页数据都会在LRU链表中,而且,当链表中某一个缓存页被访问了,也会把这个对应的描述数据移动到LRU链表的头部。
这样一来,每当Buffer Pool中的缓存页被占满的时候,就可以从LRU链表的尾部来直接拿一个缓存页,他就是被访问最少的一个。
在这里插入图片描述

预读机制导致的LRU链表隐患

什么是预读机制? 哪些情况下会触发呢?为什么需要预读机制?
简单一点来说,就是当访问数据库其中一些数据页的时候,并且刚好触发了预读的规则,那么mysql会把相邻的数据页都加载到缓存中去。但是这些数据页不一定是你真正要访问的数据,就会导致把LRU链表中的热点数据给挤到链表的队末,导致热点数据被淘汰掉。
有两种情况会被触发的规则,一种是有个变量innodb_read_ahead_threshold,这个变量的值,默认是56。如果按照顺序访问了一个区中多个数据页,达到了这个数量级的话,就会触发预读机制。把下一个相邻区中的所有数据都给加载到缓存中去。
还有一种是Buffer Pool中如果缓存了一个区中的连续13个数据页,而且这些数据页都是被频繁访问的,也会直接触发预读机制,把这个区中的所有数据页都加载到缓存中。这个是由innodb_random_read_ahead来控制的,默认是OFF,关闭状态。
全表扫描

基于冷热数据分离的思想设计LRU链表

上面说了,当有些不一定使用的缓存页混入了LRU链表中出现了问题。
所以真正的LRU链表,会被拆分为两部分,一部分是热数据,一部分是冷数据。冷数据占比默认情况是37%,可以通过innodb_old_blocks_pct参数控制的,他默认是37 。
如图:
在这里插入图片描述
当数据第一次加载的时候,会把缓存页放在冷数据区域的头部。
既然刚开始的时候,是默认放在冷数据区域中,那么肯定有规则是要挪到热数据区域的。
这个规则就是,当一个缓存页被加载到冷数据区域头部,如果1s之后还会再次访问的话。就会把这个缓存页挪动到热数据区域的头部。
那为什么不是再次访问之后就立刻就挪到头部呢? 是这样,既然我们加载了这个缓存页,那么肯定是可能在短时间被访问的,所以查询了一次之后并不能说明是被频繁访问的。如果1s之后还能被访问,就证明这些数据是热点数据。
这样一来的话就可以解决上面的热点数被挤到LRU链表尾部的问题了。哪些被预读机制和全盘扫描机制加载到LRU链表冷数据区域的缓存页,1s之后没有进行访问的话,就会一直都呆在冷数据区域。
当缓存页不够用的时候,就可以直接从冷数据区域的尾部来淘汰一部分缓存页,刷入磁盘就可以了。
还有一点,冷热数区域是没有固定的节点位置,当冷数据区的缓存页被放到热数据区之后。热数据区的数据肯定就会被往后挤咯。那么自然就被挤到冷数据区了。因为冷热数据区是按照百分比来划分的。

LRU链表热数据区域的优化

我们现在应该都知道,热数据区域的缓存页都是比较容易被访问的。那么既然都是容易被访问的,那本来就处于热数据区域头部附近的,那些缓存页,被访问的时候,还需要再次移动到头部吗?
确实不用,只有热数据区域的后4/1被访问的时候,才会直接将其移动到热数据区域的头部,这样可以减少节点的移动,进而减少内存消耗。

刷新脏页到磁盘

上面说过,当数据页变成脏页后,是存在flush链表中的。
而后台有一个专门的线程,每隔一段时间就负责吧脏页刷新到磁盘中去,这样可以不影响用户的请求。 主要有两种方式。
一种是从LRU链表的冷数据区尾部刷新一部分缓存页到磁盘。
另一种是从flush链表中刷新一部分页面到磁盘中。刷新的速率取决于当时的系统忙不忙。
但是有的时候刷新比较慢,导致用户在查询数据更新缓存页的时候没有可以用的空缓存页使用。这时候就要尝试在 LRU链表的冷数据区尾部看看有没有可以直接释放掉的未修改页面。如果没有的话就不得不将 LRU链表尾部的脏数据页先刷新到磁盘才行。但是与磁盘的交互是很费时间的。
极端情况下有可能出现,用户的请求导致批量的从flush链表刷新数据到磁盘的情况。这就需要另一种机制来处理了。我们后面再讲。

多个Buffer Pool实例

Buffer Pool的本质是InnoDB向操作系统申请的一块连续的内存空间,当多线程访问的时候。就需要对各种链表加锁处理啥的,那这样一来如果Buffer Pool特别大,访问请求特别多的情况下,肯定会影响处理速度。
所以当Buffer Pool特别大的时候,我们可以把它们拆分为多个Buffer Pool,每个Buffer Pool又都是不相关的实例,它们都是独立的,独立的申请内存空间,独自维护,独自管理各种链表什么的。这样一来多线程访问不同的缓存池就不会受影响,从而提高并发访问的处理能力。通过这个参数设置。
[server]
innodb_buffer_pool_instances = 2
需要注意的是,并不是Buffer Pool实例越多越好,分别对缓存池进行管理也是一笔不小的开销。所以innodb默认:当innodb_buffer_pool_size的值小于1G的时候设置多个实例是无效的,InnoDB会默认把innodb_buffer_pool_instances 的值修改为1
也就是说,当缓存池设置的大于等于1G的时候,才可以分为多个实例。

Buffer Pool实例的chunk机制

msyql在5.7.5版本之后,支持了Buffer Pool在服务器运行过程中进行动态调整。
实现这个首先我们要先记得Buffer Pool的本质是InnoDB向操作系统申请的一块连续的内存空间。那么想要实现动态调整的话,就把这个Buffer Pool的下级再次拆分,拆分一个chunk的概念。一个Buffer Pool其实是由多个chunk组成的,一个chunk就代表一片连续的空间。 这些chunk的缓存页,还是通过一套链表来进行维护。
如图:
在这里插入图片描述

查看buffer pool的状态

通过SHOW ENGINE INNODB STATUS 语句
mysql> SHOW ENGINE INNODB STATUS\G

(...省略前边的许多状态)
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 13218349056;
Dictionary memory allocated 4014231
Buffer pool size 786432
Free buffers 8174
Database pages 710576
Old database pages 262143
Modified db pages 124941
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 6195930012, not young 78247510485
108.18 youngs/s, 226.15 non-youngs/s
Pages read 2748866728, created 29217873, written 4845680877
160.77 reads/s, 3.80 creates/s, 190.16 writes/s
Buffer pool hit rate 956 / 1000, young-making rate 30 / 1000 not 605 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 710576, unzip_LRU len: 118
I/O sum[134264]:cur[144], unzip sum[16]:cur[0]
--------------
(...省略后边的许多状态)

我们来详细看一下这里边的每个值都代表什么意思:

Total memory allocated :代表 Buffer Pool 向操作系统申请的连续内存空间大小,包括全部控制块、缓
存页、以及碎片的大小。
Dictionary memory allocated :为数据字典信息分配的内存空间大小,注意这个内存空间和 Buffer Pool
没啥关系,不包括在 Total memory allocated 中。
Buffer pool size :代表该 Buffer Pool 可以容纳多少缓存 页 ,注意,单位是 页 !
Free buffers :代表当前 Buffer Pool 还有多少空闲缓存页,也就是 free链表 中还有多少个节点。
Database pages :代表 LRU 链表中的页的数量,包含 young 和 old 两个区域的节点数量。
Old database pages :代表 LRU 链表 old 区域的节点数量。
Modified db pages :代表脏页数量,也就是 flush链表 中节点的数量。
Pending reads :正在等待从磁盘上加载到 Buffer Pool 中的页面数量。
当准备从磁盘中加载某个页面时,会先为这个页面在 Buffer Pool 中分配一个缓存页以及它对应的控制块,
然后把这个控制块添加到 LRU 的 old 区域的头部,但是这个时候真正的磁盘页并没有被加载进来, Pending
reads 的值会跟着加1。
Pending writes LRU :即将从 LRU 链表中刷新到磁盘中的页面数量。
Pending writes flush list :即将从 flush 链表中刷新到磁盘中的页面数量。
Pending writes single page :即将以单个页面的形式刷新到磁盘中的页面数量。
Pages made young :代表 LRU 链表中曾经从 old 区域移动到 young 区域头部的节点数量。
这里需要注意,一个节点每次只有从 old 区域移动到 young 区域头部时才会将 Pages made young 的值加
1,也就是说如果该节点本来就在 young 区域,由于它符合在 young 区域1/4后边的要求,下一次访问这个页
面时也会将它移动到 young 区域头部,但这个过程并不会导致 Pages made young 的值加1。
Page made not young :在将 innodb_old_blocks_time 设置的值大于0时,首次访问或者后续访问某个处
在 old 区域的节点时由于不符合时间间隔的限制而不能将其移动到 young 区域头部时, Page made not
young 的值会加1。
这里需要注意,对于处在 young 区域的节点,如果由于它在 young 区域的1/4处而导致它没有被移动到
young 区域头部,这样的访问并不会将 Page made not young 的值加1。
youngs/s :代表每秒从 old 区域被移动到 young 区域头部的节点数量。
non-youngs/s :代表每秒由于不满足时间限制而不能从 old 区域移动到 young 区域头部的节点数量。
Pages read 、 created 、 written :代表读取,创建,写入了多少页。后边跟着读取、创建、写入的速
率。
Buffer pool hit rate :表示在过去某段时间,平均访问1000次页面,有多少次该页面已经被缓存到
Buffer Pool 了。
young-making rate :表示在过去某段时间,平均访问1000次页面,有多少次访问使页面移动到 young 区
域的头部了。
需要大家注意的一点是,这里统计的将页面移动到 young 区域的头部次数不仅仅包含从 old 区域移动到
young 区域头部的次数,还包括从 young 区域移动到 young 区域头部的次数(访问某个 young 区域的节
点,只要该节点在 young 区域的1/4处往后,就会把它移动到 young 区域的头部)。
not (young-making rate) :表示在过去某段时间,平均访问1000次页面,有多少次访问没有使页面移动
到 young 区域的头部。
需要大家注意的一点是,这里统计的没有将页面移动到 young 区域的头部次数不仅仅包含因为设置了
innodb_old_blocks_time 系统变量而导致访问了 old 区域中的节点但没把它们移动到 young 区域的次数,
还包含因为该节点在 young 区域的前1/4处而没有被移动到 young 区域头部的次数。
LRU len :代表 LRU链表 中节点的数量。
unzip_LRU :代表 unzip_LRU链表 中节点的数量(由于我们没有具体唠叨过这个链表,现在可以忽略它的
值)。
I/O sum :最近50s读取磁盘页的总数。
I/O cur :现在正在读取的磁盘页数量。
I/O unzip sum :最近50s解压的页面数量。
I/O unzip cur :正在解压的页面数量。
这些大概看一下就行了,真到用的时候可以再查。

预告

篇幅问题, 下一章节开始介绍,缓存页和索引的关系,缓存页是如何形成索引的,索引的具体构成。

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

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

相关文章

总结20个Python接单赚钱的平台,兼职月入6000+_让你早日实现财富自由

今天就给大家盘点几个基本入门接私活的资源,让你轻松学python,实现经济独立。 一、Python兼职种类: 接私活刚学会python那会,就有认识的朋友介绍做一个网站的私活,当时接单赚了4K,后又自己接过开发网站后…

Delphi5实现随机数生成并查找最大值

效果图 输入框不可修改 设置edit控件的readonly属性为true。 生成随机数 Randomize 函数通过获取系统时钟的当前时间(或其他系统特定的随机源)来自动设置随机数生成器的种子。这样,每次程序运行时,由于系统时间的不同&#xff…

NLP之词的向量化

文章目录 前言One-hot编码one-hot编码-缺点 word2vec-词向量基于语言模型的训练方式基于窗口——CBOW基于窗口——SkipGram 前言 向量对于机器学习非常重要,大量的算法都需要基于向量来完成。对于机器来说,字符是没有含义的,只是有区别。只使用字符无法去…

爬虫开发中AttributeError的快速解决方法

在网络爬虫开发过程中,AttributeError是一个常见且令人头疼的问题。这个错误通常是由于尝试访问一个对象中不存在的属性而引发的。本文将概述如何快速定位和解决AttributeError,并提供使用爬虫代理IP和多线程技术提高爬取效率的示例代码。 概述 Attrib…

mysql 数据库空间统计sql

mysql 数据库空间统计 文章目录 mysql 数据库空间统计说明一、数据库存储代码二、查询某个数据库的所有表的 代码总结 说明 INFORMATION_SCHEMA Table Reference 表参考 information_schema是‌MySQL中的一个特殊数据库,它存储了关于所有其他数据库的元数据信息。…

物理机 gogs+jenkins+sonarqube 实现CI/CD

一、部署gogs_0.11.91_linux_amd64.tar.gz gogs官网下载&#xff1a;https://dl.gogs.io/ yum -y install mariadb-serversystemctl start mariadbsystemctl enable mariadbuseradd gittar zxvf gogs_0.11.91_linux_amd64.tar.gzcd gogsmysql -u root -p < scripts/mysql.…

xLua | xLua Framework | 2 加载

0. 基础 0.1 不同加载模式 测试用 编辑器模式&#xff1b;打包模式&#xff1b;更新模式 public enum GameMode {EditorMode,PackageBundle,UpdateMode, } 0.2 加载资源步骤与接口 private void LoadAsset(string assetName, Action<Object> action) {if (AppConst.G…

c++ 求解质因数(细节详解)

定义 这里先来了解几个定义&#xff08;如已了解&#xff0c;可直接看下一个板块&#xff09; 因数&#xff1a;又称为约数&#xff0c;如果整数a除以整数b&#xff08;b0&#xff09;的商正好是是整数而没有余数&#xff0c;我们就说b是a的因数 质数&#xff1a;又称为素数…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十章 Linux设备树

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

儿童洗衣机什么牌子质量好?五款质量上乘机型推荐

在当今繁忙的生活中&#xff0c;儿童洗衣机已成为我们日常生活中不可或缺的家电。但是&#xff0c;面对市场上众多品牌的儿童洗衣机&#xff0c;那么&#xff0c;到底儿童洗衣机哪个牌子好&#xff1f;本次我将在这篇文章中探讨儿童洗衣机的选购策略&#xff0c;以帮助大家找到…

Logitech Media Server已更名为Lyrion Music Server

还以为是个新软件&#xff0c;折腾之后来才发现 &#xff0c;Lyrion Music Server 原名叫 Logitech Media Server&#xff0c;只是现在它已不再由 Logitech 拥有和维护&#xff0c;已完全移交给社区&#xff0c;因此更名&#xff0c;但简称依然还是 LMS。镜像目前还是延续了 lo…

Python Flask入门到精通:详细教程和实战案例

前言 Flask是一个轻量级的Web框架&#xff0c;用于快速开发Web应用程序。它的设计理念是简洁、灵活和易于扩展&#xff0c;非常适合于从简单的单页应用到复杂的大型项目。通过Flask&#xff0c;可以创建各种Web应用程序&#xff0c;比如博客、电子商务网站、RESTful API等。 …

在 LCD 上显示 png 图片-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

在 LCD 上显示 png 图片 PNG 简介 无损压缩&#xff1a;PNG 使用 LZ77 派生算法进行无损压缩&#xff0c;确保图像质量不受损&#xff0c;且压缩比高 体积小&#xff1a;通过高压缩比&#xff0c;PNG 文件体积小&#xff0c;适合网络传输 索引彩色模式&#xff1a;PNG-8 格式…

结合el-upload上传组件,验证文件格式及大小

结合el-upload上传组件&#xff0c;验证文件格式及大小 效果如下&#xff1a; 代码如下&#xff1a; upgradeFirmwareInfo.vue页面 <template><div><el-dialog title"新增固件升级包" :visible.sync"dialogFormVisible"top"7vh&qu…

一年八百倍!刘邦不装杯!——早读(逆天打工人爬取热门微信文章解读)

台风格美&#xff0c;是比较倾向内陆的&#xff0c;大家注意安全 引言Python 代码第一篇 洞见 读懂了刘邦的人性哲学&#xff0c;你迟早脱离底层第二篇 看看新闻了 不小心越写越俗结尾 引言 这行情我TM真的越来越看不懂 现在的互联网太恐怖了 以前还好 很多散户都是懵懂懂的 现…

Java语言程序设计基础篇_编程练习题**15.28(显示一个转动的风扇)

**15.28(显示一个转动的风扇) 编写一个程序显示一个转动的风扇&#xff0c;如图15-33c所示。Pause、Resume和Reverse按钮用于暂停、继续和反转风扇的转动 可修改编程练习题14_9的代码 习题思路&#xff1a; 新建一个BorderPane&#xff0c;一个Pane和一个HBox&#xff0c;P…

javafx的ListView代入项目的使用

目录 1. 创建一个可观察的列表&#xff0c;用于存储ListView中的数据,这里的User是包装了用户的相关信息。 2.通过本人id获取friendid&#xff0c;及好友的id&#xff0c;然后用集合接送&#xff0c;更方便直观一点。 3.用for遍历集合&#xff0c;逐个添加。 4.渲染器&…

Python+Pytest+Allure+Yaml+Pymysql+Jenkins+GitLab运行原理

PythonPytestAllureYamlPymysqlJenkinsGitLab运行原理逻辑及调用关系 GitLab代码仓&#xff1a; Jenkins工作空间&#xff1a; 代码&#xff1a; 测试报告展示&#xff1a;

CTF ssrf 基础入门 (一)

0x01 引言 我发现我其实并不是很明白这个东西&#xff0c;有些微妙&#xff0c;而且记忆中也就记得Gopherus这个工具了&#xff0c;所以重新学习了一下&#xff0c;顺便记录一下吧 0x02 辨别 我们拿到一个题目&#xff0c;他的名字可能就是题目类型&#xff0c;但是也有可能…

Python3网络爬虫开发实战(1)爬虫基础

一、URL 基础 URL也就是网络资源地址&#xff0c;其满足如下格式规范 scheme://[username:password]hostname[:port][/path][;parameters][?query][#fragment] scheme&#xff1a;协议&#xff0c;常用的协议有 Http&#xff0c;https&#xff0c;ftp等等&#xff1b;usern…