21 天 Python 计划:MySQL事务四大隔离级别深度剖析
文章目录
- 一、事务
- 1.1 什么是事务?
- 1.2 事务的四大特性
- 二、事务并发存在的问题
- 2.1 脏读(dirty read)
- 2.2 不可重复读(unrepeatable read)
- 2.3 幻读
- 三、事务的四大隔离级别实践
- 3.1 读未提交(Read Uncommitted)
- 3.1 已提交读(READ COMMITTED)
- 3.3 可重复读(Repeatable Read)
- 3.4 串行化(Serializable)
- 四、MySql隔离级别的实现原理
- 4.1 读未提交(Read Uncommitted)
- 4.2 串行化(Serializable)
- 4.3 MVCC的实现原理
- 隐式字段
- undo日志
- 快照读&当前读
- Read View
- 4.4 已提交读(READ COMMITTED) 存在不可重复读问题的分析历程
- 4.5 可重复读(Repeatable Read)解决不可重复读问题的一次分析
- 查询1执行过程分析
- 回到事务C,执行查询2
- 锁相关概念
- 4.6 不同隔离级别下的幻读分析
- 4.7 RR 级别解决幻读分析
- 五、总结
Python是一种强大且易于学习的编程语言。通过这个21天的计划,我们将逐步深入MySQL事务四大隔离级别深度剖析。无论你是初学者还是有一定基础的开发者,这个计划都将帮助你巩固和扩展你的Python知识。
在学习本篇之前,我们先复习一下前面的内容:
day1:Python下载和开发工具介绍
day2:数据类型、字符编码、文件处理
day3:基础语法与课外练习
day4:函数简单介绍
day5:模块与包
day6:常用模块介绍
day7:面向对象
day8:面向对象高级
day9:异常处理
day10:网络编程
day11:并发编程
day12:MySQL数据库初识
day13:MySQL库相关操作
day14:MySQL表相关操作
day15:MySQL中DML与权限管理
day16:MySQL数据备份与Python操作实战指南
day17:MySQL视图、触发器、存储过程、函数与流程控制
day18:使用SQLAlchemy 中的ORM查询
day19:MySQL索引机制从基础到应用
一、事务
1.1 什么是事务?
事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。
1.2 事务的四大特性
- 原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。
- 一致性:指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
- 隔离性:多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。
- 持久性:表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。
二、事务并发存在的问题
事务并发执行存在什么问题呢,换句话说就是,一个事务是怎么干扰到其他事务的呢?看例子吧~
假设现在有表:
CREATE TABLE `account` (`id` int(11) NOT NULL,`name` varchar(255) DEFAULT NULL,`balance` int(11) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `un_name_idx` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表中有数据:
2.1 脏读(dirty read)
假设现在有两个事务A、B:
假设现在A的余额是100,事务A正在准备查询Jay的余额,这时候,事务B先扣减Jay的余额,扣了10,最后A 读到的是扣减后的余额。
由上述情况可以发现,事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读。
2.2 不可重复读(unrepeatable read)
假设现在有两个事务A和B:
事务A先查询Jay的余额,查到结果是100,这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务,事务A再去查询Jay的账户余额发现变成了90。
事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。
2.3 幻读
假设现在有两个事务A、B:
事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录,这时候,事务B开启,插入一条id=4的记录,并且提交了,事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。
事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
三、事务的四大隔离级别实践
既然并发事务存在脏读、不可重复、幻读等问题,InnoDB实现了哪几种事务的隔离级别应对呢?
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 串行化(Serializable)
3.1 读未提交(Read Uncommitted)
想学习一个知识点,最好的方式就是实践之。好了,我们去数据库给它设置读未提交隔离级别,实践一下吧~
先把事务隔离级别设置为read uncommitted,开启事务A,查询id=1的数据
set session transaction isolation level read uncommitted;
begin;
select * from account where id =1;
结果如下:
这时候,另开一个窗口打开mysql,也把当前事务隔离级别设置为read uncommitted,开启事务B,执行更新操作
set session transaction isolation level read uncommitted;
begin;
update account set balance=balance+20 where id =1;
接着回事务A的窗口,再查account表id=1的数据,结果如下:
可以发现,在读未提交(Read Uncommitted) 隔离级别下,一个事务会读到其他事务未提交的数据的,即存在脏读问题。事务B都还没commit到数据库呢,事务A就读到了,感觉都乱套了。实际上,读未提交是隔离级别最低的一种。
3.1 已提交读(READ COMMITTED)
为了避免脏读,数据库有了比读未提交更高的隔离级别,即已提交读。
把当前事务隔离级别设置为已提交读(READ COMMITTED),开启事务A,查询account中id=1的数据
set session transaction isolation level read committed;
begin;
select * from account where id =1;
另开一个窗口打开mysql,也把事务隔离级别设置为read committed,开启事务B,执行以下操作
set session transaction isolation level read committed;
begin;
update account set balance=balance+20 where id =1;
接着回事务A的窗口,再查account数据,发现数据没变:
我们再去到事务B的窗口执行commit操作:
commit;
最后回到事务A窗口查询,发现数据变了:
由此可以得出结论,隔离级别设置为已提交读(READ COMMITTED) 时,已经不会出现脏读问题了,当前事务只能读取到其他事务提交的数据。但是,你站在事务A的角度想想,存在其他问题吗?
提交读的隔离级别会有什么问题呢?在同一个事务A里,相同的查询sql,读取同一条记录(id=1),读到的结果是不一样的,即不可重复读。所以,隔离级别设置为read committed的时候,还会存在不可重复读的并发问题。
3.3 可重复读(Repeatable Read)
如果你的老板要求,在同个事务中,查询结果必须是一致的,即老板要求你解决不可重复的并发问题,怎么办呢?老板,臣妾办不到?来实践一下可重复读(Repeatable Read) 这个隔离级别吧~
哈哈,步骤1、2、6的查询结果都是一样的,即repeatable read解决了不可重复读问题,是不是心里美滋滋的呢,终于解决老板的难题了~
RR级别是否解决了幻读问题呢?
再来看看网上的一个热点问题,有关于RR级别下,是否解决了幻读问题?我们来实践一下:
由图可得,步骤2和步骤6查询结果集没有变化,看起来RR级别是已经解决幻读问题了~
但是呢,RR级别还是存在这种现象:
其实,上图如果事务A中,没有update account set balance=200 where id=5;
这步操作,select * from account where id>2
查询到的结果集确实是不变,这种情况没有幻读问题。但是,有了update这个骚操作,同一个事务,相同的sql,查出的结果集不同,这个是符合了幻读的定义~
这个问题,亲爱的朋友,你觉得它算幻读问题吗?
3.4 串行化(Serializable)
前面三种数据库隔离级别,都有一定的并发问题,现在放大招吧,实践SERIALIZABLE隔离级别。
把事务隔离级别设置为Serializable,开启事务A,查询account表数据
set session transaction isolation level serializable;
select @@tx_isolation;
begin;
select * from account;
另开一个窗口打开mysql,也把事务隔离级别设置为Serializable,开启事务B,执行插入一条数据:
set session transaction isolation level serializable;
select @@tx_isolation;
begin;
insert into account(id,name,balance) value(6,'Li',100);
执行结果如下:
由图可得,当数据库隔离级别设置为serializable的时候,事务B对表的写操作,在等事务A的读操作。其实,这是隔离级别中最严格的,读写都不允许并发。它保证了最好的安全性,性能却是个问题~
四、MySql隔离级别的实现原理
实现隔离机制的方法主要有两种:
- 读写锁
- 一致性快照读,即 MVCC
MySql使用不同的锁策略(Locking Strategy)/MVCC来实现四种不同的隔离级别。RR、RC的实现原理跟MVCC有关,RU和Serializable跟锁有关。
4.1 读未提交(Read Uncommitted)
官方说法:
SELECT statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used. Thus, using this isolation level, such reads are not consistent.
读未提交,采取的是读不加锁原理。
- 事务读不加锁,不阻塞其他事务的读和写
- 事务写阻塞其他事务写,但不阻塞其他事务读;
4.2 串行化(Serializable)
官方的说法:
InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. If autocommit is enabled, the SELECT is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plain SELECT to block if other transactions have modified the selected rows, disable autocommit.)
所有SELECT语句会隐式转化为SELECT ... FOR SHARE
,即加共享锁。
读加共享锁,写加排他锁,读写互斥。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞。
4.3 MVCC的实现原理
MVCC,中文叫多版本并发控制,它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。它的实现依赖于隐式字段、undo日志、快照读&当前读、Read View,因此,我们先来了解这几个知识点。
隐式字段
对于InnoDB存储引擎,每一行记录都有两个隐藏列DB_TRX_ID、DB_ROLL_PTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列DB_ROW_ID。
- DB_TRX_ID,记录每一行最近一次修改(修改/更新)它的事务ID,大小为6字节;
- DB_ROLL_PTR,这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;
- DB_ROW_ID,单调递增的行ID,大小为6字节;
undo日志
事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响。
undo日志是逻辑日志。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert记录,当update一条记录时,它记录一条对应相反的update记录。
存储undo日志的地方,就是回滚段。
多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(DB_ROLL_PTR)连一条Undo日志链。
我们通过例子来看一下~
mysql> select * from account ;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 1 | Jay | 100 |
+----+------+---------+
1 row in set (0.00 sec)
假设表accout现在只有一条记录,插入该该记录的事务Id为100
如果事务B(事务Id为200),对id=1的该行记录进行更新,把balance值修改为90
事务B修改后,形成的Undo Log链如下:
快照读&当前读
- 快照读:读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读,如:
select * from account where id>2;
- 当前读:读取的是记录数据的最新版本,显示加锁的都是当前读
select * from account where id>2 lock in share mode;
select * from account where id>2 for update;
Read View
Read View就是事务执行快照读时,产生的读视图。
事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把它们放到一个列表里。
Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~
为了下面方便讨论Read View可见性规则,先定义几个变量
- m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List。
- min_limit_id:m_ids事务列表中,最小的事务ID
- max_limit_id:m_ids事务列表中,最大的事务ID
如果DB_TRX_ID < min_limit_id,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。
如果DB_TRX_ID > m_ids列表中最大的事务id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。
如果 min_limit_id <=DB_TRX_ID<= max_limit_id,需要判断m_ids.contains(DB_TRX_ID),如果在,则代表Read View生成时刻,这个事务还在活跃,还没有Commit,你修改的数据,当前事务也是看不见的;如果不在,则说明,你这个事务在Read View生成之前就已经Commit了,修改的结果,当前事务是能看见的。
注意啦!! RR跟RC隔离级别,最大的区别就是:RC每次读取数据前都生成一个ReadView,而RR只在第一次读取数据时生成一个ReadView。
4.4 已提交读(READ COMMITTED) 存在不可重复读问题的分析历程
我觉得理解一个新的知识点,最好的方法就是居于目前存在的问题/现象,去分析它的来龙去脉~ RC的实现也跟MVCC有关,RC是存在重复读并发问题的,所以我们来分析一波RC吧,先看一下执行流程
假设现在系统里有A,B两个事务在执行,事务ID分别为100、200,并且假设存在的老数据,插入事务ID是50哈~
事务A 先执行查询1的操作
# 事务A,Transaction ID 100
begin ;
查询1:select * from account WHERE id = 1;
事务 B 执行更新操作,id =1记录的undo日志链如下
begin;
update account set balance =balance+20 where id =1;
回到事务A,执行查询2的操作
begin ;
查询1:select * from account WHERE id = 1;
查询2:select * from account WHERE id = 1;
查询2执行分析:
事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)在活跃,所以ReadView的m_ids列表内容就是[200]
由上图undo日志链可得,最新版本的balance为1000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务A)不可见。
我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录200,所以这个版本可见,因此,查询2的结果,就是返回balance=100这个记录~~
我们回到事务B,执行提交操作,这时候undo日志链不变
begin;
update account set balance =balance+20 where id =1;
commit
再次回到事务A,执行查询3的操作
begin ;
查询1:select * from account WHERE id = 1;
查询2:select * from account WHERE id = 1;
查询3:select * from account WHERE id = 1;
查询3执行分析:
事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)已经提交,不载活跃,所以ReadView的m_ids列表内容就是空的了。
所以事务A直接读取最新纪录,读取到balance =120这个版本的数据。
所以,这就是RC存在不可重复读问题的过程啦有不理解的地方可以多读几遍哈
4.5 可重复读(Repeatable Read)解决不可重复读问题的一次分析
我们再来分析一波,RR隔离级别是如何解决不可重复读并发问题的吧~
你可能会觉得两个并发事务的例子太简单了,好的!我们现在来点刺激的,开启三个事务~
假设现在系统里有A,B,C两个事务在执行,事务ID分别为100、200,300,存量数据插入的事务ID是50~
# 事务A,Transaction ID 100
begin ;
UPDATE account SET balance = 1000 WHERE id = 1;
# 事务B,Transaction ID 200
begin ; //开个事务,占坑先
这时候,account表中,id =1记录的undo日志链如下:
# 事务C,Transaction ID 300
begin ;
//查询1:select * from account WHERE id = 1;
查询1执行过程分析
事务C在执行SELECT语句时,会先生成一个ReadView。因为事务A(100)、B(200)在活跃,所以ReadView的m_ids列表内容就是[100,200]。
由上图undo日志链可得,最新版本的balance为1000,它的事务ID为100,在活跃事务列表里,所以当前事务(事务C)不可见。
我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录100,所以这个版本可见,因此,查询1的结果,就是返回balance=100这个记录~~
接着,我们把事务A提交一下:
# 事务A,Transaction ID 100
begin ;
UPDATE account SET balance = 1000 WHERE id = 1;
commit;
在事务B中,执行更新操作,把id=1的记录balance修改为2000,更新完后,undo 日志链如下:
# 事务B,Transaction ID 200
begin ; //开个事务,占坑先
UPDATE account SET balance = 2000 WHERE id = 1;
回到事务C,执行查询2
# 事务C,Transaction ID 300
begin ;
//查询1:select * from account WHERE id = 1;
//查询2:select * from account WHERE id = 1;
查询2:执行分析:
在RR级别下,执行查询2的时候,因为前面ReadView已经生成过了,所以直接服用之前的ReadView,活跃事务列表为[100,200].
由上图undo日志链可得,最新版本的balance为2000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务C)不可见。
我们继续找下一个版本,balance为1000这行记录,事务Id为100,也在活跃事务列表里,所以当前事务(事务C)不可见。
继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录100,所以这个版本可见,因此,查询2的结果,也是返回balance=100这个记录~~
锁相关概念
(一)共享锁与排他锁
InnoDB 实现了标准的行级锁,包括共享锁(S 锁)和排他锁(X 锁):
共享锁(S 锁):允许持锁事务读取一行。
排他锁(X 锁):允许持锁事务更新或者删除一行。
锁的兼容性规则如下:
若事务 T1 持有行 r 的 S 锁,事务 T2 请求 r 的 S 锁会立即被允许,此时 T1 和 T2 都持有 r 行的 S 锁;事务 T2 请求 r 的 X 锁不能被立即允许。
若 T1 持有 r 的 X 锁,T2 请求 r 的 X 锁和 S 锁都不能被立即允许,T2 必须等待 T1 释放 X 锁,因为 X 锁与任何锁都不兼容。
(二)记录锁(Record Locks)
记录锁是最简单的行锁,仅锁住一行,如 SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE。记录锁永远加在索引上,即使表没有索引,InnoDB 也会隐式创建一个索引并使用该索引实施记录锁。记录锁会阻塞其他事务对其插入、更新、删除操作。
示例记录锁的事务数据:
RECORD LOCKS space id 58 page no 3 n bits 72 index PRIMARY
of table test
.t
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc 'O;;
2: len 7; hex b60000019d0110; asc ;;
(三)间隙锁(Gap Locks)
间隙锁是加在两个索引之间、第一个索引之前或最后一个索引之后间隙的锁。它锁住的是一个区间,而非区间内的每条数据。间隙锁只阻止其他事务插入到间隙中,不阻止其他事务在同一间隙上获得间隙锁,所以 gap x lock 和 gap s lock 作用相同。
(四)Next - Key Locks
Next - key 锁是记录锁和间隙锁的组合,指加在某条记录以及这条记录前面间隙上的锁。
4.6 不同隔离级别下的幻读分析
(一)RC 级别存在幻读分析
假设 account 表有 4 条数据,在 RC 隔离级别下:
开启事务 A,执行当前读,查询 id > 2 的所有记录。
开启事务 B,插入 id = 5 的一条数据,插入成功后修改 id = 3 的记录。
事务 B 可以插入 id = 5 的数据,但更新 id = 3 的数据时陷入阻塞,这表明事务 A 在执行当前读时在 id = 3 和 id = 4 这两条记录上加了锁,但未对 id > 2 这个范围加锁。
事务 B 陷入阻塞后,事务 A 再次执行当前读操作时出现死锁。因为事务 B 在 insert 时会在新纪录(id = 5)上加锁,事务 A 再次执行当前读想获取 id > 3 的记录,需在 id = 3、4、5 这 3 条记录上加锁,而 id = 5 这条记录已被事务 B 锁住,事务 A 被事务 B 阻塞,同时事务 B 还在等待事务 A 释放 id = 3 上的锁,最终产生死锁。
由此可见,RC 隔离级别下,加锁的 select、update、delete 等语句使用的是记录锁,其他事务的插入依然可以执行,因此会存在幻读。
4.7 RR 级别解决幻读分析
假设 account 表有 4 条数据,在 RR 隔离级别下:
开启事务 A,执行当前读,查询 id > 2 的所有记录。
开启事务 B,插入 id = 5 的一条数据,事务 B 执行插入操作时阻塞。这是因为事务 A 在执行 select … lock in share mode 时,不仅在 id = 3、4 这 2 条记录上加了锁,还在 id > 2 这个范围上也加了间隙锁。
由此可见,RR 隔离级别下,加锁的 select、update、delete 等语句会使用间隙锁 + 临键锁,锁住索引记录之间的范围,避免范围间插入记录,从而避免产生幻影行记录。
五、总结
通过这个21天的Python计划,我们涵盖了MySQL事务四大隔离级别深度剖析。希望这些内容能帮助你更好地理解和使用Python。继续学习和实践,你将成为一名优秀的Python开发者!
相关文章:
21 天 Python 计划:MySQL事务四大隔离级别深度剖析
文章目录 一、事务1.1 什么是事务?1.2 事务的四大特性 二、事务并发存在的问题2.1 脏读(dirty read)2.2 不可重复读(unrepeatable read)2.3 幻读 三、事务的四大隔离级别实践3.1 读未提交(Read Uncommitted…...
IO多路复用沉浸式体验
这篇文章主要讲解一下IO多路复用常见问题,包含常见面试题,对你有帮助的话可以留个赞和关注嘛?谢谢大家支持! 1.epoll 相比于 select/poll 的优点有哪些? 高效的数据结构:epoll使用红黑树管理fd࿰…...
音视频学习(三十三):GOP详解
GOP 概念 GOP(图像组)是视频编码中一组帧的集合(按相关性分组),它从一个关键帧(I帧)开始,后面跟随若干个参考帧(P帧)和预测帧(B帧)。其结构决定了视频帧的压…...
部署YUM仓库
目录 一.YUM 1.1yum概述 1.2yum的实现 1.3yum服务的组成 1.4yum服务实现过程 1.5yum配置文件位置 二.yum相关命令 三.搭建yum仓库的方式 3.1使用HTTP方式搭建yum仓库 准备工作(服务端和客户端都需要做) 服务端 客户端 3.2使用ftp方式搭建yu…...
中位数学习(低估它了)
-----------------------------------------------------------------中位数------------------------------------------------------- 中位数有一个很好的性质:假设有一批数据,你想找一个数,使得这批数据与它差的绝对值的和最小࿰…...
音视频转换器 AV 接口静电保护方案
方案简介 音视频转换器是将音视频(AV)信号转换成其他格式或信号类型的设备或软件。 它能够实现大多数视频、音频以及图像格式之间的转换,包括但不限于 RMVB、AVI、 MP4、MOV 等常见格式,同时也支持将不同采样率、位深度、声道数…...
蓝桥杯嵌入式第十二届省赛程序设计1(超简单版)
此程序只需要会C语言数组,结构体(struct),for , if , switch(也可以用if)就能够实现。 引脚设置: 引脚配置(参照笔记): 代码部分: /* USER CODE END Header */ /* Includes ------------------…...
CSS 链接样式学习笔记
在网页设计中,链接(<a> 标签)是不可或缺的元素,通过 CSS 可以对链接进行丰富的样式设置,从而提升用户体验和页面美观度。以下是关于 CSS 链接样式的详细学习笔记。 一、链接的四种状态 链接有四种不同的状态&a…...
有ts文件却无法ts出来解决办法
一开始报错是报这个,但是我其实完全看不懂为什么 原因是这个 打开某个test就行了...
javaSE.Lambda表达式
如果一个接口中有且只有一个待实现的抽象方法,那么我们可以将匿名内部类简写为Lambda表达式。 简写规则 标准格式: (【参数类型 参数名称,】...) -> {代码语句, 包括返回值} 只有一行花括号{}可以省略。…...
Web渗透之文件包含漏洞
文件包含漏洞原理 1、源代码 <?php$filename $_GET[filename]; include $filename; //或include_once,require,require_onceecho "欢迎来到PHP的世界.";?> 2、利用条件 php.ini中alllow_url_fopenOn(默认开启)和allow_url_includeOff(默认关闭)要开启…...
费马引理和罗尔定理
cheer 向……欢呼,使高兴,欢呼,欢呼,愉快 前言区间平均值费马引理罗尔三步万能构造原函数的方法什么时候用罗尔定理计划拉格朗日需要记忆的不等式柯西中值定理泰勒高阶导数判断极值最后 前言 继续学习。今天争取把讲义和作业题都…...
【合新通信】浸没式液冷中低成本冷媒开发的最新进展
浸没式液冷光模块是一种结合高效散热技术与光通信的新型解决方案,主要用于数据中心、超算中心等高密度计算场景。其核心特点是通过将光模块直接浸入绝缘冷却液中(如矿物油、氟化液等),实现高效散热和节能降耗。低成本冷却液的研发…...
【开发记录】服务外包大赛记录
参加服务外包大赛的A07赛道中,最近因为频繁的DEBUG,心态爆炸 记录错误 以防止再次出现错误浪费时间。。。 2025.4.13 项目在上传图片之后 会自动刷新 没有等待后端返回 Network中的fetch /upload显示canceled. 然而这是使用了VS的live Server插件才这样&…...
智能指针之设计模式1
本文探讨一下智能指针和GOF设计模式的关系,如果按照设计模式的背后思想来分析,可以发现围绕智能指针的设计和实现有设计模式的一些思想体现。当然,它们也不是严格意义上面向对象的设计模式,毕竟它们没有那么分明的类层次体系&…...
Spring Boot 中应用的设计模式
Spring Boot 中应用的设计模式详解 Spring Boot 作为 Spring 框架的扩展,广泛使用了多种经典设计模式。以下是主要设计模式及其在 Spring Boot 中的具体应用: 一、创建型模式 1. 工厂模式 (Factory Pattern) 应用场景: BeanFactory 和 Ap…...
23种GoF设计模式
GoF(Gang of Four)设计模式是由四位计算机科学家 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著的书籍《Design Patterns: Elements of Reusable Object-Oriented Software》中提出的设计模式 目录 一、创建型模式(Cre…...
Python实例题:Python实现中文错别字高亮系统
目录 Python实例题 题目 安装依赖库 代码实现 代码解释 运行思路 注意事项 Python实例题 题目 Python实现中文错别字高亮系统 安装依赖库 在开始之前,你需要安装 pycorrector 和 rich 库。可以使用以下命令进行安装: pip install pycorrecto…...
【第三十一周】ViT 论文阅读笔记
ViT 摘要Abstract文章信息引言方法Patch EmbeddingPatch Position EmbeddingTransformer EncoderMLP Head整体架构CNN的归纳偏置 代码实现实验结果总结 摘要 本篇博客介绍了Vision Transformer(ViT),这是一种突破性的图像分类模型ÿ…...
射频(RF)静电放电防护方案
方案简介 射频(RF)是 Radio Frequency 的缩写,表示可以辐射到空间的电磁频率,频率 范围从 300kHz~300GHz 之间。射频就是射频电流,简称 RF,它是一种高频交流变化 电磁波的简称。射频天线是一…...
【redis进阶三】分布式系统之主从复制结构(1)
目录 一 为什么要有分布式系统? 二 分布式系统涉及到的非常关键的问题:单点问题 三 学习部署主从结构的redis (1)创建一个目录 (2)进入目录拷贝两份原有redis (3)使用vim修改几个选项 (4)启动两个从节点服务器 (5)建立复制,要想配…...
排序(1)
排序(1) 日常生活中,有很多场景都会用到排序。比如你买东西,在购物软件就有几种展现方式,按照评论数量给你排序出来,让你选,还是说按照价钱高低排序出来让你选。 排序其实是一种为了更好解决问…...
NR 5G中的N5接口
N5接口的定义: Reference point between the PCF and an AF or TSN AF. 即N5 PCF和AF之间的参考点。 AF Application Function 应用功能,指应用层的各种服务,可以是运营商内部的应用如Volte AF(类似4G的Volte As)、也可以是第三方的AF&…...
STM32自学进阶指南:从入门到精通的成长路径 | 零基础入门STM32第九十九步
主题内容教学目的/扩展视频自学指导通过数据手册和搜索引擎查找资料,独立解决问题以积累经验和提升能力。自学过程中应保持敬畏之心,不断总结未知领域,持续进步。师从洋桃电子,杜洋老师 📑文章目录 一、自学指导全景图1.1 学习路线对比1.2 关键学习策略二、待探索技术领域…...
利用 Python 进行股票数据可视化分析
在金融市场中,股票数据的可视化分析对于投资者和分析师来说至关重要。通过可视化,我们可以更直观地观察股票价格的走势、交易量的变化以及不同股票之间的相关性等。 Python 作为一种功能强大的编程语言,拥有丰富的数据处理和可视化库…...
用 Vue.js 构建基础购物车:从 0 到 1 的实战解析
在当今数字化购物的浪潮中,购物车功能已成为电商平台不可或缺的一部分。它不仅承担着记录用户所选商品的重任,还需提供流畅的交互体验和精准的计算逻辑。本文将深入探讨如何利用 Vue.js 这一强大的 JavaScript 框架,逐步搭建一个基础但功能完…...
MapSet常用的集合类(二叉搜索树,哈希表)
Set集合 Set的核心特点: Set继承了Collection。 保存的元素不会重复。 保存的元素不能修改。 保存的元素无序,和List不同,如果有两个:List {1,2,3},List {2,1,3}&…...
五种IO模型
1、通信的本质: 通过网络通信的学习,我们能够理解网络通信的本质是进程间通信,而进程间通信的本质就是IO。 IO也就是input和output。当读取条件不满足的时候,recv会阻塞。write写入数据时,会将数据拷贝到缓冲区中&am…...
路由器开启QOS和UPNP的作用
QOS 的作用 保障关键业务带宽:可根据网络应用的重要性分配带宽。比如在家庭网络中,当多人同时使用网络时,将视频会议等实时性要求高的关键业务设置为高优先级,确保其能获得足够带宽,避免卡顿,而文件下载等…...
学习MySQL的第九天
纸上得来终觉浅 绝知此事要躬行 数据处理的增删查改 一、添加数据 添加数据有两种方式,一种是一条一条的添加数据,另一种是通过对其他表的查询,将查询的结果插入到表中;第一种方式又可以分为三种方式:…...
怎么免费下载GLTF/GLB格式模型文件,还可以在线编辑修改
现在非常流行glb格式模型,和gltf格式文件,可是之类模型网站非常非常少 1,咱们先直接打开http://glbxz.com 官方glb下载网站 glbxz.com 2 可以搜索,自己想要的模型关键词 3,到自己想下载素材页面 4,…...
高效数据拷贝方法总结
1.系统/语言层面的高效拷贝 内存拷贝优化 使用memcpy(C/C)或类似函数进行大块内存拷贝 利用SIMD指令(如AVX/SSE)进行向量化拷贝 2.零拷贝技术 文件映射(mmap) - 将文件映射到内存空间 发送文件描述符而非数据本身(Unix域套接字) 使用sendfile系统调用(文件到套接字直接传…...
C 语言 第八章 文件操作
目录 文件操作 文件和流的介绍 C 输入 & 输出 C 文件的读写 创建/打开文件 写入文件 fputc 函数 fputs 函数 fprintf 函数 实例: 读取文件 fgets函数 实例: 关闭文件 文件操作 文件和流的介绍 变量、数组、结构体等数据在运行时存储于内存…...
开发一款游戏需要哪些岗位角色参与?
常见分类 1. 游戏策划(Game Designer) 核心职责:设计游戏的玩法、规则、内容和整体体验。 具体工作: 系统设计:设计游戏的战斗、经济、成长、社交等核心系统。 数值设计:平衡角色属性、装备数值、经济系…...
大模型面经 | 手撕多头注意力机制(Multi-Head Attention)
大家好,我是皮先生!! 今天给大家分享一些关于大模型面试常见的面试题,希望对大家的面试有所帮助。 往期回顾: 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题一) 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题二) 大模型面经 | 春招、秋招算法…...
二叉树的初步学习
前言 对于二叉树的学习不想其他数据结构一样,直接学习他的结构的构建。单纯的一个二叉树在实际中没什么作用,除非是加了限制条件的,比如大名鼎鼎的红黑树。但是对于初学者而言,刚开始就学习红黑树,会让你刚接触就想放…...
Tkinter菜单和工具栏的设计
在这一章中,我们将深入探讨如何在Tkinter应用程序中设计菜单和工具栏。菜单和工具栏是桌面应用程序中常见的界面元素,它们为用户提供了便捷的操作方式。通过这一章的学习,您将能够在您的Tkinter应用中添加菜单栏和工具栏,提升用户体验。 6.1 菜单栏的设计 菜单栏是应用程…...
windows中搭建Ubuntu子系统
windows中搭建虚拟环境 1.配置2.windows中搭建Ubuntu子系统2.1windows配置2.1.1 确认启用私有化2.1.2 将wsl2设置为默认版本2.1.3 确认开启相关配置2.1.4重启windows以加载更改配置 2.2 搭建Ubuntu子系统2.2.1 下载Ubuntu2.2.2 迁移位置 3.Ubuntu子系统搭建docker环境3.1安装do…...
Docker 部署 Kafka 完整指南
Docker 部署 Kafka 完整指南 本指南将详细介绍如何使用 Docker 部署 Kafka 消息队列系统,包括单节点和集群模式的部署方式。 1. 单节点部署 (Zookeeper Kafka) 1.1 创建 docker-compose.yml 文件 version: 3.8services:zookeeper:image: bitnami/zookeeper:3.8…...
java学习总结(if switch for)
一.基本结构 1.单分支if int num 10; if (num > 5) {System.out.println("num 大于 5"); } 2.双分支if-else int score 60; if (score > 60) {System.out.println("及格"); } else {System.out.println("不及格"); } 3.多分支 int…...
解释:指数加权移动平均(EWMA)
指数加权移动平均(EWMA, Exponential Weighted Moving Average) 是一种常用于时间序列平滑、异常检测、过程控制等领域的统计方法。相比普通移动平均,它对最近的数据赋予更高权重,对旧数据逐渐“淡化”。 ✅ 一、通俗理解 想象你…...
open harmony多模组子系统分析
multimodalinput是open harmony的核心输入子系统,负责统一管理触摸屏,键盘,鼠标,手势,传感器等多种 输入源,提供标准化事件分发机制。其核心 目标是通过统一的事件处理框架,实现跨设备ÿ…...
Hello Java!
1. Java发展史 1.1 计算机编程语言分类 机器语言:电子机器能够直接识别的语言,无需经过翻译,计算机内部就有相应的电路来完成它;从使用的角度来看,机器语言是最低级的语言。 机器语言。指令以二进制代码形式存在。 汇…...
vue 入门:生命周期
文章目录 vue组件的生命周期创建阶段更新阶段销毁阶段生命周期钩子函数 vue组件的生命周期 创建阶段、销毁阶段:只会执行一次更新阶段:会执行多次 创建阶段 beforeCreate 在实例初始化之后,数据观测(data observer)…...
C#容器源码分析 --- Dictionary<TKey,TValue>
Dictionary<TKey, TValue> 是 System.Collections.Generic 命名空间下的高性能键值对集合,其核心实现基于哈希表和链地址法(Separate Chaining)。 .Net4.8 Dictionary<TKey,TValue>源码地址: dictionary…...
yum的基本操作和vim指令
在我们的手机端或者Windows上下载软件,可以在相应的应用商店或者官网进行下载,这样对于用户来说十分的方便和便捷。而在Linux上,也有类似的安装方式,我们来一一了解一下。 Linux安装软件的3种方法 源代码安装 在Linux下安装软件…...
MCU刷写——HEX与S19文件互转详解及Python实现
工作之余来写写关于MCU的Bootloader刷写的相关知识,以免忘记。今天就来聊聊Hex与S19这这两种文件互相转化,我是分享人M哥,目前从事车载控制器的软件开发及测试工作。 学习过程中如有任何疑问,可底下评论! 如果觉得文章内容在工作学习中有帮助到你,麻烦点赞收藏评论+关注走…...
深入探讨避免MQ消息重复消费的策略与实现
引言 随着微服务架构的流行,消息队列(Message Queue, MQ)作为系统间异步通信的重要手段,被广泛应用于各种场景。然而,在使用MQ的过程中,一个不容忽视的问题是消息可能被重复消费。这不仅可能导致数据不一致…...
定制一款国密浏览器(8):SM3 摘要算法
上一章我们讲到了铜锁和 BoringSSL,本章从最简单的国密算法 SM3 摘要算法入手,说明一下 SM3 算法的移植要点。 SM3 算法本身并不复杂,详细算法说明参考《GB∕T 32905-2016信息安全技术 SM3密码杂凑算法》这份文档。因为铜锁开源项目有实现代码,直接照搬过来。 将 crypto/…...
【Docker基础】Compose 使用手册:场景、文件与命令详解
文章目录 一、什么是 Docker Compose二、为什么需要 Docker Compose三、Docker Compose 使用步骤 / 核心功能步骤核心功能: 四、Docker Compose 的使用场景五、Docker Compose 文件(docker-compose.yml)文件语法版本文件基本结构及常见指令常…...