【MySQL06】【MVCC】

news2024/11/27 2:16:42

文章目录

  • 一、前言
  • 二、事务
    • 1. 事务的四大特性(ACID)
      • 1.1. 原子性
      • 1.2. 一致性
      • 1.3. 持久性
      • 1.4. 隔离性
    • 2. 脏写、脏读、不可重复读、幻读
    • 3. 隔离级别
  • 三、MVCC
    • 1. 版本链
    • 2. ReadView
    • 3. 二级索引与 MVCC
  • 四、关于 purge
  • 五、参考内容

一、前言

最近在读《MySQL 是怎样运行的》、《MySQL技术内幕 InnoDB存储引擎 》,后续会随机将书中部分内容记录下来作为学习笔记,部分内容经过个人删改,因此可能存在错误,如想详细了解相关内容强烈推荐阅读相关书籍


二、事务

1. 事务的四大特性(ACID)

1.1. 原子性

一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做

即事务是执行的最小单元,执行结果只有两个,要么成功,要么失败回滚。

1.2. 一致性

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。数据不会因为事务的执行而遭到破坏。

比如,当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统在运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。

1.3. 持久性

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,接下来的任何操作和故障都不应该影响到已提交的事务执行结果。

例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

1.4. 隔离性

一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

2. 脏写、脏读、不可重复读、幻读

  1. 脏写:如果一个事务修改了另一个未提交事务修改过的数据,就意味着发生了脏写。所有的隔离级别都不会出现这种情况。

  2. 脏读:脏读又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。

    例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。

  3. 不可重复读:不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。

    例如:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

    解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据

  4. 幻读:在同一事务内,两次相同的查询返回的数据条目数量不同,在RU、RC、RR级别下,都会出现幻读

    例如:事务T1读取一次表中数据总量,事务T2修改了表中数据总量(插入或者删除了数据)。这是事务T1再次读取表中数据总量,发现和第一次读取的总量不同,好像产生了幻觉。
    亦或者,在可重复读的隔离级别下,事务T1查询了记录a,发现不存在,准备插入记录a,但是此时事务T2开启并插入了记录a,此时事务T1才开始准备插入,但是T1插入会失败,因为库里已经存在记录a,此时T1即便再次查询记录a也无法查询到。这是因为mvcc的特性,由于T2比T1晚开启,T1是不会读取到T2修改的记录。

    解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。

注意:

  1. 脏写、脏读、不可重复读、幻读,解决该问题所需要的隔离级别,高低是:脏写 < 脏读 (读已提交)< 不可重复读(可重复读) < 幻读(可串行化)
  2. 不可重复读针对的是多次读取内容不同,幻读针对的是多次读取,内容条数不同
  3. 快照读:普通的select操作,是从 ReadView 中读取数据,读取的可能是历史数据
  4. 当前读:insert、update、delete、select…for update这种操作,读取的总是当前的最新数据

3. 隔离级别

隔离级别解释
读未提交(READ UNCOMMITTED)这是事务最低的隔离级别,它允许事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。
读已提交 (READ COMITTED)保证一个事务修改的数据提交后才能被另外一个事务读取。 另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻读。
可重复读(REPEATABLE READ)这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。它除了保证-一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读) (MySql 默认就是这个级别)
可串行化 (SERIALIZABLE)这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。但是不建议使用,他将事务完全按照串行处理。

三、MVCC

1. 版本链

在【MySQL02】【 InnoDB 记录存储结构】 提到过,InnoDB 中每条记录都有两个必要的隐藏列(row_id 不是必须的)

  1. trx_id:一个事务每次对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给 trx_id
  2. roll_point:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到 undo 日志中。这个隐藏列相当于一个指针,通过它可以找到修改前的信息。

我们以下表为例(主键叫 number 而不叫id 仅仅是为了与 后面的 事务 id 区分)

CREATE TABLE `hero` (
  `number` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `country` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`number`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

当我们执行如下SQL 插入一条记录:

INSERT INTO hero (name, country) VALUES ('刘备', '蜀');

假设插入该记录的事务id 为 80 ,那么此刻此条记录的示意图如下:

insert undo 日志只在事务回滚时发送作用,当事务提交后,该类型的undo 日志就没用了,他所占用的 Undo Log Segment 也会被系统回收,虽然真正的 insert undo 日志占用的存储空间被回收了,但是 roll_pointer 的值并不会被清除。

在这里插入图片描述


假设之后两个事务id 分别为 100, 200 的事务对这条记录进行 update 操作,操作流程如下图:

执行顺序trx 100trx 200
1begin;
2begin;
3update hero set name = ‘关羽’ where number = 1;
4update hero set name = ‘张飞’ where number = 1;
5commit;
6update hero set name = ‘赵云’ where number = 1;
7update hero set name = ‘诸葛亮’ where number = 1;
8commit;

每对记录修进行一次改动,都会记录一条 undo 日志,每条 undo 日志也都有一个 roll_pointer 属性(insert 操作对应的 undo 日志没有该属性,因为 insert 操作的记录并没有更早的版本),通过这个属性可以将这些 undo 日志串成一个链表,所以现在情况如下图:
在这里插入图片描述

在每次更新该记录后,都会将旧值放到一条 undo 日志中(也就是该记录的一个旧版本)随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,这个链表称为版本链。版本链的头节点就是当前记录的最新值

另外,每个版本中还包含生成该版本时对应的事务id,InnoDB会利用这个记录的版本链来控制并发事务访问相同记录时的行为,这种机制称为 多版本并发控制(MVVC)

在 update 操作产生的 undo 日志中,只会记录一些索引列以及被更新的列的信息,并不会记录全部列,上述图片内容仅仅是为了方便理解
如对于 trx_id = 80 的那条 undo 日志来说,本身并没有记录 country 列信息。如果一条 undo 日志没有记录某一列,则说明某一列的值与上个版本相同,通过版本链去上个版本查找对应值即可,如果各个版本的 undo 日志都没有记录该列的值,则说明该列从未被修改过,对应列的值跟聚簇索引中列的值相同。

2. ReadView

对于 READ UNCOMMITTED 隔离级别的事务来说,由于可以读取到未提交事务修改的记录,所以- 直接读取记录的最新版本就好;

对于 SERIALIZABLE 隔离级别的事务来说,InnoDB 采用加锁的方式来访问记录;

对于 READ COMITTED 和 REPEATABLE READ 隔离级别的事务来说,都必须要保证读到已经提交的事务修改过的记录,也就是说如果另一个事务已经修改了记录但尚未提交,则不能直接读取最新版本的记录,因此这里的核心问题就是:需要判断版本链中的哪个版本是当前事务可见的。为此 InnoDB 提出了 Read View (一致性视图)的概念。

ReadView 中主要包含4个比较重要的内容

  • m_ids:在生成 ReadView 时,当前系统中活跃的读写事务的事务id列表。
  • min_trx_id:在生成 ReadView 时,当前系统中活跃的读写事务中最小的事务id,也就是 m_ids 中的最小值
  • max_trx_id:在生成 ReadView 时,系统应该分配给下一个事务的事务id值,这个值会比 m_ids 中的最大值大1(因为是分配给下一个事务)
  • creator_trx_id:生成该 ReadView 的事务的事务id。(只有在对表中记录做修改时,即增删改时才会为事务分配唯一事务的id,否则一个事务的id 值都默认为 0)

在有了这个 ReadView 后,在访问某条记录后,只需要根据如下步骤判断记录某个版本是否可见:

  1. 如果某个本访问版本的 trx_id 属性值和 ReadView中的 creator_trx_id 值相同,则说明当前事务在访问他自己修改过的记录,所以该版本可以被当前事务访问。
  2. 如果被访问版本的 trx_id 小于 ReadView 中的 min_trx_id 值,则表明生成该版本的事务在当前事务生成 ReadView 前就已经提交,所以该版本可以被当前事务访问。
  3. 如果被访问版本的 trx_id 属性值大于或等于 ReadView 中的 max_trx_id 值则表明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。
  4. 如果被访问版本的 trx_id 属性值在 ReadView 的 min_trx_id 和 max_trx_id 之间,则需要判断 trx_id 属性值是否在 m_ids 列表中,如果在说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可被访问,否则则说明该版本事务已经被提交,该版本可以被访问。

如果某个版本的数据对当前事务不可见,则顺着版本链找到下一个版本的数据,并继续执行上面的步骤判断记录的可见性;依次类推,如果记录的最后一个版本也不可见则意味着该条记录对当前事务完全不可见,查询结果就不该包含这条记录。

而 READ COMITTED 和 REPEATABLE READ 隔离级别之间非常大的一个区别就是生成 ReadView 的时机并不相同:

  • READ COMITTED 在每次读取数据前都生成一个 ReadView
  • REPEATABLE READ 在第一次读取数据时生成一个 ReadView

注意:

  1. 在事务执行过程中,只有第一次执行增删改操作时才会分配 trx_id ,在此之前,事务的默认id都是0。
  2. 在 REPEATABLE READ 隔离级别下,如果通过 START TRANSACTION WITH CONSISTENT SNAPSHOT 开启事务会在执行该语句后立即生成一个 ReadView,而不是在执行第一条 select 语句时才执行。

3. 二级索引与 MVCC

只有聚簇索引记录中才有 trx_id 和 roll_pointer 隐藏列,如果查询某个语句是使用二级索引来执行查询的,要如何判断可见性?
以下面内容为例:

BEGIN;
SELECT name FROM hero where name = '刘备';

假设 name 为名为 idx_name 的二级索引,判断可见性的过程大致如下:

  1. 二级索引页面的 Page Header 部分有一个名为 PAGE_MAX_TRX_ID 的属性,每当对该页面中记录执行增删改操作时,如果执行该操作的事务的事务id大于 PAGE_MAX_TRX_ID 属性值,则将 PAGE_MAX_TRX_ID 属性值更新为当前事务id,即 PAGE_MAX_TRX_ID 代表修改该二级索引页面的最大的事务id是多少。当一个 SELECT语句访问某个二级索引记录时,首先会看一下对应的 ReadView 的min_trx_id 是否大于该页面的 PAGE_MAX_TRX_ID,如果是,则说明该页面中的所有记录都对该 ReadView 可见,否则执行下一步,在回表后判断可见性。
  2. 利用二级索引记录中的主键值进行回表操作,得到对应的聚簇索引记录后再按照上面的方式找到对该 ReadView 可见的第一个版本,然后判断该版本中相应的二级索引列的值是否与利用该二级索引查询时的值相同。如果是就认为这条记录满足二级索引条件,再进行其他Where 条件判断(如果有),否则就跳过该记录。

四、关于 purge

insert undo 日志在事务提交之后就可以释放掉了,而 update undo 日志由于还需要支持 MVCC,因此不能立即删除掉。

在 MySQL05【 undo 日志】 有提到过对于没有被重用的 Undo 页面链表来说,链表的第一个页面(first undo page)在真正写入 undo 日志前,会填充 Undo Page Header、Undo Log Segment Header、Undo Log Header 三部分,之后才会正式写入日志,因此一个事务写的一组 undo 日志中都有一个 Undo Log Header 部分。Undo 页面链表如下图:
在这里插入图片描述

这个 Undo Log Header 中有一个名为 TRX_UNDO_HISTORY_NODE 的属性,表示一个名为 History 链表的节点。当一个事务提交后就会把这个事务执行过程中产生的这一组 update undo 日志插入到 History 链表的头部。

在 MySQL05【 undo 日志】 中提到过,每个回滚段都对应一个名为 Rollback Segment Header 的页面,这个页面中有如下两个属性:

  • TRX_RSEG_HISTORY :表示 History 链表的基节点
  • TRX_RSEG_HISTORY_SIZE :表示 History 链表占用的页面数量

也就是说每个回滚段都有一个 History链表,一个事务在某个回滚段中写入的一组 update undo 日志在该事物提交后,就会加到这个回滚段的History链表中。系统中可能存在很多回滚段,也就意味着可能有很多个 History 链表。

不过这些加入到History 链表的 update undo 日志所占用的存储空间也没有释放,他们总归是需要释放的。


为了支持 MVCC, delete mark 操作仅仅是在记录上打一个删除标记,并没有真正将记录删除。
在一组 undo 日志中的 Undo Log Header 部分有一个名为 TRX_UNDO_DEL_MARKS 的属性,用来标记本组 undo 日志中是否包含因 delete mark 操作而产生的undo 日志。为了节约存储空间,需要在合适的时候需要把 update undo 日志以及仅仅被标记为删除的记录彻底删除掉,这个删除操作就成为 purge。

所谓合适的时候是如何判断的?

update undo 日志和被标记为删除的记录只是为了支持 MVCC 而存在的,只要系统中最早产生的那个 ReadView 不再访问他们,他们的使用就结束了,就可以删除了。而当生成这个 ReadView 的事务已经提交时,就可以断定该 ReadView 肯定就不需要访问该事务运行过程中产生的 undo 日志了(因为该事物所改动的记录的最新版本均对该 ReadView 可见)


InnoDB 为此做了两件事:

  1. 在一个事务提交时,会为这个事务生成一个名为 事务no 的值,该值用来表示事务提交的顺序,先提交的事务小,后提交的事务大。

    而在一组 undo 日志中对应的 Undo Log Header 部分有一个名为 TRX_UNDO_TRX_NO 的属性。当事务提交时,就把该事物对应的事务no 填入到该属性中,因为事务no代表各个事物提交的顺序,而 History 链表又是按照事务提交的顺序来排列各组 undo 日志的,所以 History 链表中的各组 undo 日志也是按照对应的事务no来排序的。

  2. 一个RedaView 结构除了包含前面说的几个属性,还包含一个事务no 的属性。在生成一个 ReadView 时, 会把比当前系统中最大的事务no值还大1的值赋值给这个属性。

    InnoDB将当前系统中所有的 ReadVidw 按照创建时间顺序连成了一个链表。当执行 purge 操作时(后台有专门的线程执行),就把系统中最早生成的 ReadView 给取出来,如果当前系统中不存在 ReadView,就现场创建一个(新创建的 ReadView 的 事务no 肯定比当前已经提交的事务的事务no大)。然后从各个回滚段的 History链表中取出事务 no 值较小的各组 undo 日志。如果一组 undo 日志的事务no小于当前系统最早生成的 ReadView 的事务 no,就意味着该组 undo 日志包含因 delete mark 操作而产生的 undo 日志(TRX_UNDO_DEL_MARKS 的值为1),那么也需要将对应的标记为删除的记录给彻底删除。

    需要注意的是:当前系统中最早生成的 ReadView 决定了 purge 操作中可以清理那些 update undo 日志以及打了删除标记的记录。如果某个事务使用了 REPEATABLE READ 隔离级别,那么该事务会一直使用最初产生的 ReadView。假如这个事务运行了很久,一直没有提交,那么最早生成的 ReadView会一直不释放,系统中的 update undo 日志和打了删除标记的记录就会越来越多,表空间对应的文件也会越来越大,一条记录的版本链就会越来越长,从而影响系统性能。

在 MySQL05【 undo 日志】 中提到过 在执行 DELETE 或 UPDATE 语句时并不会立即把对应的记录从页面中完全删除(包括聚簇索引记录和二级索引记录)而是执行一个 delete mark 操作,之所以没有完全删除,就是为了给 MVCC 服务。

五、参考内容

书籍:《MySQL是怎样运行的——从根儿上理解MySQL》、《MySQL技术内幕 InnoDB存储引擎 》
https://blog.csdn.net/filling_l/article/details/112854716

如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

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

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

相关文章

网安小贴士(20)网络物理隔离技术

前言 网络物理隔离技术是一种网络安全技术&#xff0c;其核心原理是通过物理方式将网络或网络设备分隔开来&#xff0c;以确保数据安全、降低风险并提升系统的整体安全性。以下是对网络物理隔离技术原理与应用的详细解析&#xff1a; 一、网络物理隔离技术原理 物理断开&#x…

gradle学习及问题

一、下载安装 参考&#xff1a;https://blog.csdn.net/chentian114/article/details/123344839 1、下载Gradle并解压 安装包&#xff1a;gradle-6.7-bin.zip 可以在idea的安装目录查看自己适配的版本 路径&#xff1a;D:\IDEA2021.3\plugins\gradle\lib 下载地址&#xff1a…

java之log4j反序列化

1 审计思路 以Log4j漏洞审计为案例,谈一谈审计如何快速的锁定通用型漏洞 1.1 确定源码是否引用了漏洞所属的开源组件 该项目是一个maven项目,直接在Pom文件中搜索log4j的jar包及版本引用问题,如果该版本受影 响,进入下一步 1.2 寻找漏洞的入口 1.3 逐个排查入口是否有效…

手持式气象站:便携科技,掌握微观气象的利器

手持式气象站&#xff0c;顾名思义&#xff0c;是一种可以随身携带的气象监测设备。它小巧轻便&#xff0c;通常配备有温度、湿度、风速、风向、气压等多种传感器&#xff0c;能够实时测量并显示各种气象参数。不仅如此&#xff0c;它还具有数据存储、数据传输、远程控制等多种…

【python学习】思考-如何在PyCharm中编写一个简单的Flask应用示例以及如何用cProfile来对Python代码进行性能分析

引言 Python中有两个流行的Web框架&#xff1a;Django和Flask。Django是一个高级的Python Web框架&#xff0c;它鼓励快速开发和干净、实用的设计&#xff1b;Flask是一个轻量级的Web应用框架&#xff0c;适用于小型到大型应用。以下是使用Flask创建一个简单应用的基本步骤cPro…

Spring Framework各种jar包官网下载2024年最新下载官方渠道。

Spring其实就是一个大家族&#xff0c;它包含了Spring Framework&#xff0c;Spring Boot等一系列技术&#xff0c;它其实就是由许许多多的jar包构成&#xff0c;我们要使用Spring的框架&#xff0c;就要去下载支持这个框架的jar包即可。 1.官网下载Spring Framework的jar包 官…

C++系列-List的使用

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 测试代码 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<list> using namespace std; void test_list1() {list<int> lt1 { 10,2,3,3,4,3…

Dockerfile制作部署wordpress-6.6

目录 一. 环境准备 二. 准备对应的配置文件 三. 编写Dockerfile 四. 构建镜像 五. 配置MySQL 六. 安装wordpress 七. 扩展 一. 环境准备 localhost192.168.226.25 rocky_linux9.4 Docker version 27.0.3 关闭防火墙和selinux&#xff0c;进行时间同步。 安装docker…

配置RIPv2的认证

目录 一、配置IP地址、默认网关、启用端口 1. 路由器R1 2. 路由器R2 3. 路由器R3 4. Server1 5. Server2 二、搭建RIPv2网络 1. R1配置RIPv2 2. R2配置RIPv2 3. Server1 ping Server2 4. Server2 ping Server1 三、模拟网络攻击&#xff0c;为R3配置RIPv2 四、在R…

微软史诗级的蓝屏

本周经历了微软的蓝屏&#xff0c;一直到周末还在加班处理公司的问题。 个人终端受到的影响较大&#xff0c;服务器上也受到了影响。因为蓝屏的事情导致不少麻烦&#xff0c;据同事说因为蓝屏的问题&#xff0c;MGH 的手术安排也受到了影响。 目前我们也在着手处理有部署 Wind…

《书生大模型实战营第3期》入门岛 学习笔记与作业:Git 基础知识

文章大纲 Git 是什么&#xff1f;-- 分布式版本控制系统版本控制系统简介Git 基本概念1. 安装 Git1.1 Windows 系统1.2 Linux 系统 2. Git 托管平台3. 常用 Git 操作4. tips4.1 全局设置 vs. 本地设置4.2 如何配置4.3 验证设置4.4 Git 四步曲 5. 常用插件6. 常规开发流程 作业其…

leetcode hot100 (面试复习用)

数组 最大子数组和 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 示例&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4]输出&#xff1a;6解释&#xff1…

《算法笔记》总结No.9——高效配招

一.打表 一种经典的空间换时间方式&#xff1a;即将所有可能用到的结果实现计算出来&#xff0c;这样后面用到的时候直接可以查表获得。具体来说有3种方式&#xff1a; 1.计算所有结果 这个是最常用到的用法&#xff0c;例如在一个需要查询大量Fibonacci数F(n)的问题中&#x…

分布式Apollo配置中心搭建实战

文章目录 环境要求第一步、软件下载第二步、创建数据库参考文档 最近新项目启动&#xff0c;采用Apollo作为分布式的配置中心&#xff0c;在本地搭建huanj 实现原理图如下所示。 环境要求 Java版本要求&#xff1a;JDK1.8 MySql版本要求&#xff1a;5.6.5 Apollo版本要求&…

kettle从入门到精通 第七十九课 ETL之kettle kettle读取数据库BLOB字段转换为文件

上一课我们讲解了如何将文件以二进制流的方式写入数据库&#xff0c;本节课我们一起学习下如何将二进制数据读取为文件。 1、将二进制流转换为文件这里主要用到了步骤【文本文件输出】。表输入步骤从表中读取blob字段&#xff0c;java代码定义二进制流转换为文件的全路径&#…

微星主板 B450M 设置 Legacy 启动模式

问题来源 我安装阵列卡需要Legacy启动模式 主板设置 微星主板BIOS不熟悉&#xff0c;找了好久。 在 BIOS -> Setting -> Advanced -> Windows OS Configuaration 中把 BIOS CSM/UEFI Mode 设置成 CSM 模式 在 Setting -> Boot 中把 Boot mode select 改成带 “L…

在 CI/CD Pipeline 中实施持续测试的最佳实践!

随着软件开发周期的不断加快&#xff0c;持续集成&#xff08;CI&#xff09;和持续交付/部署&#xff08;CD&#xff09;已经成为现代软件开发的重要组成部分。在这一过程中&#xff0c;持续测试的实施对于确保代码质量、提高发布效率至关重要。本文将详细介绍在CI/CD流水线中…

mac数据恢复软件哪个好用 macbook数据恢复专业软件下载 mac数据恢复概率大吗 苹果电脑数据恢复软件哪个好

作为办公的必需品&#xff0c;mac的普及率虽然比不上其他品牌的windows操作系统&#xff0c;但是使用人群也一致居高不下&#xff0c;因此&#xff0c;mac数据丢失的问题也时常发生。当数据丢失以后&#xff0c;如何找回数据成了一大难题。 一、Mac数据恢复概率大吗 一般情况下…

NSSCTF-Web题目25(RCE-构造变量)

目录 [CISCN 2019初赛]Love Math 1、题目 2、知识点 3、思路 [SWPUCTF 2023 秋季新生赛]If_else 1、题目 2、知识点 3、思路 [CISCN 2019初赛]Love Math 1、题目 2、知识点 构造变量&#xff0c;进制转换、函数利用 3、思路 打开题目&#xff0c;出现源码 代码的意思…

Xcode学习笔记

Xcode学习笔记 前言一、在Mac上安装Xcode并做点简单设置1.查看一下Xcode的版本 二、使用Xcode新建一个Playground三、swift基础-变量1.swift是什么2.变量是什么3.建立变量4.改变变量5.小帖士 四、swift基础-变量命名规范1.使用小驼峰命名法2.使用有意义且描述性的名称3.避免使用…