MySQL 事务原理:事务概述、隔离级别、MVCC
文章目录
- 一、事务
- 1.1 事务概述
- 1.2 事务控制语句
- 1.3 ACID特性
- 二、隔离级别
- 2.1 隔离级别的分类
- 2.1.1 读未提交(RU)
- 2.1.2 读已提交(RC)
- 2.1.3 可重复读(RR)
- 2.1.4 串行化
- 2.2 命令
- 2.3 并发读异常
- 2.3.1 脏读
- 2.3.2 不可重复读
- 2.3.3 幻读
- 2.3.4 丢失更新
- 2.4 区别
- 2.5 测试代码
- 三、MVCC
- 3.1 read view
- 3.2 当前读 & 快照读
- 3.3 聚集索引隐藏列
- 3.4 事务的可见性问题
- 四、redo log
- 五、undo log
一、事务
1.1 事务概述
事务:并发连接场景下,用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
MySQL的事务就是将多条SQL语句作为整体进行执行。
1)事务的目的:事务将数据库从一种一致性状态转换为另一种一致性状态;保证系统始终处于一个完整且正确的状态。
2)事务的组成:事务可由一条非常简单的 SQL 语句组成,也可以由一组复杂的SQL 语句组成。
3)事务的特征:在数据库提交事务时,可以确保要么所有修改都已经保存,要么所有修改都不保存。事务是访问并更新数据库各种数据项的一个程序执行单元。在 MySQL innodb 下,单条语句都具备事务。
1.2 事务控制语句
-- 显示开启事务
START TRANSACTION | BEGIN
-- 提交事务,并使得已对数据库做的所有修改持久化
COMMIT
-- 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
ROLLBACK
-- 创建一个保存点,一个事务可以有多个保存点
SAVEPOINT identifier
-- 删除一个保存点
RELEASE SAVEPOINT identifier
-- 事务回滚到保存点
ROLLBACK TO [SAVEPOINT] identifier
1.3 ACID特性
1)原子性(A)
事务是访问并更新数据库各种数据项的一个程序执行单元,是不可分割的工作单位。因此事务操作要么全部执行,要么全部不执行,不存在中间状态。若事务执行过程发生错误,通过 undolog 来回滚到事务初始状态。undolog 记录的是事务每步具体操作,当回滚时,回放事务具体操作的逆运算。
undo log 存放在共享表空间内,用于存储旧版本的数据。主要有两个作用:
∘ \circ ∘ 事务回滚:记录事务 DML 操作步骤,通过逆运算(逻辑取反)实现事务回滚。
∘ \circ ∘ MVCC:记录事务 DML 操作提交后产生的行数据版本信息。
2)一致性(C)
事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测(完整性约束检查);
一致性指事务将数据库从一种一致性状态转变为下一种一致性的状态,在事务执行前后,数据库完整性约束没有被破坏。一个事务单元需要提交之后才会被其他事务可见。一致性由原子性、隔离性以及持久性共同来维护的。
一致性的种类:
∘ \circ ∘ 数据一致性(数据库完整性约束 – 五大约束),必须遵守。
∘ \circ ∘ 预期一致性(逻辑一致性),可以适当破坏。例:查询是否存在,不存在写入,可能出现数据查询不存在,插入时却存在,此时会报错。
3)隔离性(I)
事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,并发事务之间不会相互影响,防止多个并发事务交叉执行导致数据不一致。
不同程度的隔离级别应对不同的现象,如脏读、不可重复读、幻读。可以通过适度破环一致性,得以提高性能。
通过 MVCC和 锁来实现:
∘ \circ ∘ MVCC :多版本并发控制,主要解决数据库中多个事务并发执行时可能出现的读写冲突和数据不一致问题。通过记录和获取行版本,而不是使用锁来限制读操作,从而实现高效并发读性能。
∘ \circ ∘ 锁:用来处理并发 DML 操作;数据库中提供粒度锁的策略,针对表(聚集索引 B+ 树)、页(聚集索引 B+ 树叶子节点)、行(叶子节点当中某一段记录行)三种粒度加锁;
4)持久性(D)
事务一旦完成,要将数据所做的变更记录下来,包括数据存储和多副本的网络备份。
事务提交后,事务 DML 操作将会持久化(写入 redolog 磁盘文件 哪一个页 页偏移值 具体数据);即使发生宕机等故障,数据库也能将数据恢复。
redolog 记录的是物理日志。事务提交后,记录事务 DML 操作对应物理页修改的内容,写入 redo log 磁盘文件。发生宕机等故障时,恢复数据库数据。
二、隔离级别
ISO 和 ANIS SQL 标准制定了四种事务隔离级别,目的在于提升数据库并发性能。MySQL innodb默认支持的隔离级别是REPEATABLE READ。
2.1 隔离级别的分类
读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。
2.1.1 读未提交(RU)
最低级别的隔离级别,事务可以读取到其他事务未提交的数据。即事务还未提交,其变更就能被其他事务看到
问题:可能导致脏读、不可重复读和幻读问题。
加锁情况:该级别下读不加锁,写自动加排他锁,写锁在事务提交或回滚后释放锁。
2.1.2 读已提交(RC)
事务只能读取到其他事务已提交的数据。即事务提交后,其变更才能被其他事务看到
问题:避免了脏读问题。但仍然可能出现不可重复读和幻读问题。
加锁情况:该级别后支持 MVCC (多版本并发控制),也就是提供一致性非锁定读(提供了不加锁的读取操作);此时读取操作读取历史快照数据;该隔离级别下读取历史版本的最新数据,所以读取的是已提交的数据。写自动加排他锁
2.1.3 可重复读(RR)
事务开始后,保证在整个事务过程中读取的数据是一致的。即事务执行过程中看到的数据,一直跟与该事务启动时看到的数据是一致的。
问题:避免了脏读和不可重复读问题,但仍然可能出现幻读问题。
加锁情况:该级别下也支持 MVCC,此时读取操作读取事务开始时的版本数据。写自动加排他锁
2.1.4 串行化
最高级别的隔离级别,事务串行执行,确保了最高程度的隔离性。即,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
问题:避免了脏读、不可重复读和幻读问题,但可能导致较高的并发性能开销。
加锁情况:该级别下给读加了共享锁,写自动加排他锁。
2.2 命令
-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者采用下面的方式设置隔离级别
SET @@tx_isolation = 'REPEATABLE READ';
SET @@global.tx_isolation = 'REPEATABLE READ';
-- 查看全局隔离级别
SELECT @@global.tx_isolation;
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- 手动给读加 S 锁
SELECT ... LOCK IN SHARE MODE;
-- 手动给读加 X 锁
SELECT ... FOR UPDATE;
-- 查看当前锁信息
SELECT * FROM information_schema.innodb_locks;
2.3 并发读异常
准备工作
DROP TABLE IF EXISTS `account_t`;
CREATE TABLE `account_t` (`id` INT(11) NOT NULL,`name` VARCHAR(255) DEFAULT NULL,`money` INT(11) DEFAULT 0,PRIMARY KEY (`id`),KEY `idx_name` (`name`)
)ENGINE = INNODB AUTO_INCREMENT=0 DEFAULT CHARSET = utf8;INSERT INTO `account_t` VALUES (7,'M',1000), (1, 'C', 1000),(2, 'B', 1000),(3, 'A', 1000);
2.3.1 脏读
一个事务读到了另一个事务未提交的修改(读到脏数据)。
不可重复读在 RU 隔离级别存在。在读写分离的场景下,可以将 slave 节点设置为 READ UNCOMMITTED。此时脏读不影响,在 slave 上查询并不需要特别精准的返回值。
例如:session B 读到了 session A 中事务未提交的脏数据。
seq | session A | session B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE account_t SET money = money - 100 WHERE name = ‘A’; | |
4 | UPDATE account_t SET money = money - 100 WHERE name = ‘A’; | |
5 | COMMIT; | COMMIT; |
2.3.2 不可重复读
事务(A) 可以读到另外一个事务(B)中提交的数据;通常发生在一个事务中两次读到的数据是不一样的情况;不可重复读在隔离级别 READ COMMITTED 存在。一般而言,不可重复读的问题是可以接受的,因为读到已经提交的数据,一般不会带来很大的问题.
例如:session B 读到了 session A 中事务提交的修改,造成两次读取同一个数据不一样。
seq | session A | session B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE account_t SET money = money - 100 WHERE name = ‘A’; | |
4 | SELECT money FROM account_t WHERE name = ‘A’; | |
5 | COMMIT; | SELECT money FROM account_t WHERE name = ‘A’; |
6 | COMMI; |
2.3.3 幻读
两次读取同一个范围内的记录得到的结果集不一样。
例如:以name 为唯一键的表,一个事务中查询 select * from table where name = 'tom';
不存在,接下来 insert into table (name) values ('tom');
出现错误,此时另外一个事务也执行了 insert 操作;
幻读在隔离级别 REPEATABLE READ 及以下存在;但是可以在 REPEATABLE READ 级别下通过读加锁(使用 next-key locking)解决;
例如:由于 session A 的事务提交了插入操作,导致 session B 两次查询范围的结果不一样。
seq | session A | session B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000); | |
4 | SELECT * FROM account_t WHERE id >= 2; | |
5 | COMMIT; | |
6 | SELECT * FROM account_t WHERE id >= 2; | |
7 | INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000); | |
8 | SELECT * FROM account_t WHERE id >= 2 LOCK IN SHARE MODE; | |
9 | COMMI; |
解决:通过读加锁(next-key locking)
seq | session A | session B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM account_t WHERE id >= 2 LOCK IN SHARE MODE; | |
4 | INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000); | |
5 | INSERT INTO account_t(id,name,money) VALUES (4,‘E’,1000); | |
6 | COMMI; | |
7 | COMMI; |
2.3.4 丢失更新
脏读、不可重复读、幻读都是一个事务写,一个事务读,由于一个事务的写导致另一个事务读到了不该读的数据。
丢失更新是两个事务都是写。丢失更新分为提交覆盖和回滚覆盖;回滚覆盖会被数据库拒绝,所以不可能产生,重点关注提交覆盖。
seq | session A | session B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT money FROM account_t WHERE name = ‘A’; | |
4 | SELECT money FROM account_t WHERE name = ‘A’; | |
5 | UPDATE account_t SET money = 1100 WHERE name = ‘A’; | |
6 | COMMIT; | |
7 | UPDATE account_t SET money = 1100 WHERE name = ‘A’; | |
8 | COMMIT; |
2.4 区别
1)脏读和不可重复读的区别在于,脏读是读取了另一个事务未提交的数据,而不可重复读是读取了另一个事务提交后的修改。本质上都是其他事务的修改影响了本事务的读取。
2)不可重复读和幻读比较类似;不可重复读是两次读取同一条记录,得到不一样的结果;而幻读是两次读取同一个范围内的记录得到的结果集不一样(可能不同个数,也可能相同个数内容不一样,比如x一行后又添加新行)。
3)不可重复读是因为其他事务进行了 update 操作,幻读是因为其他事务进行了 insert或者 delete 操作。
隔离级别 | 回滚覆盖 | 脏读 | 不可重复读 | 幻读 | 提交覆盖 |
---|---|---|---|---|---|
READ UNCOMMITTED | NO | YES | YES | YES | YES |
READ COMMITTED | NO | NO | YES | YES | YES |
REPEATABLE REA | NO | NO | NO | YES (手动加锁) | YES (手动加锁) |
SERIALIZABLE | NO | NO | NO | NO | NO |
MySQL InnoDB 引擎的默认隔离级别是可重复读,但是它可以很大程度上避免幻读现象。
1)针对快照读:通过 MVCC 方式解决了幻读。因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
2)针对当前读:是通过 next-key lock(记录锁+间隙锁)方式解决了幻读。因为当执行 select
语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
2.5 测试代码
DROP TABLE IF EXISTS `account_t`;
CREATE TABLE `account_t` (`id` INT(11) NOT NULL,`name` VARCHAR(255) DEFAULT NULL,`money` INT(11) DEFAULT 0,PRIMARY KEY (`id`),KEY `idx_name` (`name`)
)ENGINE = INNODB AUTO_INCREMENT=0 DEFAULT CHARSET = utf8;SELECT * from account_t;rollback;
INSERT INTO `account_t` VALUES (7,'M',1000), (1, 'C', 1000),(2, 'B', 1000),(3, 'A', 1000);insert into -- 脏读读取了另一个事务未提交的修改 (其他事务的修改影响了本事务的读取)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
-- 脏读事务1
UPDATE account_t SET money = money - 100 WHERE name = 'A';
-- 脏读事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- SELECT money FROM account_t WHERE name = 'B';
-- 脏读事务1
UPDATE account_t SET money = money + 100 WHERE name = 'B';
-- 脏读事务1
COMMIT;
-- 脏读事务2
-- COMMIT-- 不可重复读读取了另一个事务提交之后的修改(其他事务的修改影响了本事务的读取)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
-- 不可重复读事务2
SELECT money FROM account_t WHERE name = 'A';
-- 不可重复读事务1
UPDATE account_t SET money = money - 100 WHERE name = 'A';
-- 不可重复读事务1
COMMIT;
-- 不可重复读事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- COMMIT-- 幻读两次读取得到的结果集不一样
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
-- 幻读事务2
-- SELECT * FROM account_t WHERE id >= 2;
-- 幻读事务1
INSERT INTO account_t(id,name,money) VALUES (4,'D',1000);
-- 幻读事务1
COMMIT
-- 幻读事务2
-- SELECT * FROM account_t WHERE id >= 2;
-- COMMIT;-- 丢失更新(提交覆盖)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
-- 丢失更新事务1
SELECT money FROM account_t WHERE name = 'A';
-- 丢失更新事务2
-- SELECT money FROM account_t WHERE name = 'A';
-- UPDATE account_t SET money = 1100 WHERE name = 'A';
-- COMMIT;
-- 丢失更新事务1
UPDATE account_t SET money = 900 WHERE name = 'A';
COMMIT;
三、MVCC
多版本并发控制 MVCC(Multiversion Concurrency Control),用来实现一致性的非锁定读。非锁定读是指不需要等待访问记录 X 锁(排他锁)的释放。因此 MVCC 没有读写阻塞,只有写写阻塞,提高了并发性。
在 read committed 和 repeatable read 下,innodb 使用MVCC;但是它们对于快照数据的定义不同。
1)在 read committed 隔离级别下,对于快照数据总是读取被锁定行的最新一份快照数据;
2)而在 repeatable read 隔离级别下,对于快照数据总是读取事务开始时的行数据版本;
3.1 read view
read view 是事务进行快照读的时候产生的读视图,保存了当前事务开启时所有活跃事务的列表。
在 read committed 和 read repeatable 隔离级别下,MVCC 采用read view 来实现的,它们的区别在于创建 read view 时机不同:
1)read committed 隔离级别会在事务中每个 select 都会生成一个新的 read view,也意味着在同一个事务多次读取同一条数据可能出现数据不一致;因为在多次读取期间可能有其他事务修改了该条记录,并提交了;
2)read repeatable 隔离级别是启动事务时生成一个 readview,在整个事务读取数据都才使用这个 read view,这样保证了在事务期间读到的数据都是事务启动前的记录。
3.1.1 构成
1) m_ids :创建 read view 时,当前数据库活跃事务(已启动但未提交的事务)的事务 id 列表;
2)min_trx_id :创建 read view 时, m_ids 中的最小事务 id;
3)max_trx_id :创建 read view 时,当前数据库将为下一个事务分配的事务 id;并不一定是 m_ids 中的最大事务 id;
4)creator_trx_id :创建 read view 所在事务的 id;
3.2 当前读 & 快照读
3.2.1 当前读(Current Read)
当前读是指读取最新提交的数据。当进行当前读时,事务会读取已经提交并且已经写入到数据库中的最新数据。当前读可以获取到最新的数据,但也可能会受到并发事务的影响,因为正在执行的事务可能会修改正在被读取的数据,从而导致一致性问题。对此,当前读使用行级锁定来确保读取最新提交的数据的一致性。
-- 出现当前读的情况
-- 1
select * from table where ... lock in share mode;-- 2
select * from table where ... for update;-- 3
insert into table values(...);-- 4
update table set ?=? where ...;-- 5
delete from table where ...;
3.2.2 快照读(Snapshot Read)
快照读是指读取一个指定时间点的数据快照。当进行快照读时,事务会读取在事务开始之前已提交的数据状态,即使在事务执行期间其他事务进行了更改或提交。这意味着快照读可以提供一种一致性的视图,不受并发事务的干扰。
MVCC 的读指的是快照读(非锁定读),因为没有事务需要对历史数据进行 DML 操作。
在读已提交和可重复读的隔离级别下,对于快照数据的定义不同
∘ \circ ∘ RC 级别:读取当前事务锁定行的最新行记录。
∘ \circ ∘ RR 级别:读取启动事务时的行记录版本。
-- 出现快照读的情况
select * from table where ......
3.3 聚集索引隐藏列
1)trx_id :当某个事务对某条聚集索引记录进行修改时,将会把当前事务的 id 赋值给 trx_id;
2)roll_pointer :当某个事务对某条聚集索引记录进行修改时,会将上一个版本的记录写到 undo log,然后通过roll_pointer 指向旧版本记录,通过它可以找到修改前的记录;
3.4 事务的可见性问题
3.4.1 事务状态
1)已提交的事务
2)已启动未提交的事务
3)还没开始的事务
3.4.2 事物的可见性
事务可以看到事物本身的修改。具体可以通过如下判断:
1)trx_id < min_trx_id
:说明该记录在创建 read_view 之前已经提交,所以对当前事务可见;
2)trx_id >= max_trx_id
:说明该记录是在创建 read_view 之后启动事务生成的,所以对当前事务不可见;
)min_trx_id <= trx_id < max_trx_id
:此时需要判断是否在 m_ids 列表中:
∘ \circ ∘ 在列表中:生成该版本记录的事务仍处于活跃状态,该版本记录对当前事务不可见;
∘ \circ ∘ 不在列表中:生成该版本记录的事务已经提交,该版本记录对当前事务可见;
四、redo log
redo 日志用来实现事务的持久性;
内存中包含 redo logbuffer,磁盘中包含 redo log file;
当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务的 commit 操作完成才完成了事务的提交;
redo log 顺序写,记录的是对每个页的修改(页、页偏移量、以及修改的内容);在数据库运行时不需要对 redo log 的文件进行读取操作;只有发生宕机的时候,才会拿redo log 进行恢复。
五、undo log
undo 日志用来帮助事务回滚以及 MVCC 的功能;存储在共享表空间中;
undo 是逻辑日志,回滚时将数据库逻辑地恢复到原来的样子,根据 undo log 的记录,做之前的逆运算;比如事务中有 insert 操作,那么执行 delete 操作;对于 update 操作执行相反的 update 操作;
同时 undo 日志记录行的版本信息,用于处理 MVCC 功能
相关文章:

MySQL 事务原理:事务概述、隔离级别、MVCC
文章目录 一、事务1.1 事务概述1.2 事务控制语句1.3 ACID特性 二、隔离级别2.1 隔离级别的分类2.1.1 读未提交(RU)2.1.2 读已提交(RC)2.1.3 可重复读(RR)2.1.4 串行化 2.2 命令2.3 并发读异常2.3.1 脏读2.3…...

useEffect从入门到入土
副作用是相对于纯函数概念来说的, 除事件回调处理副作用,其他副作用尽量放在useEffect中; 组件首次渲染、有依赖项更新(Object.is方法判断)时,该useEffect触发 jsx渲染完成后立马触发useEffectÿ…...

第三章 图论 No.6负环之01分数规划与特殊建图方式
文章目录 裸题:904. 虫洞01分数规划:361. 观光奶牛特殊建图与01分数规划trick:1165. 单词环 裸题:904. 虫洞 904. 虫洞 - AcWing题库 // 虫洞是负权且单向边,道路是正权且双向边,题目较裸,判…...

九、Spring 声明式事务学习总结
文章目录 一、声明式事务1.1 什么是事务1.2 事务的应用场景1.3 事务的特性(ACID)1.4 未使用事务的代码示例1.5 配置 Spring 声明式事务学习总结 一、声明式事务 1.1 什么是事务 把一组业务当成一个业务来做;要么都成功,要么都失败…...

ResNet50卷积神经网络输出数据形参分析-笔记
ResNet50卷积神经网络输出数据形参分析-笔记 ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块 5049个卷积(3463)*31和一个全连接层 分析结果为: 输入数据形状:[10, 3, 224, 224] 最后输出结果:linear_0 [10,…...

uniapp 微信小程序 封装公共的请求js(api版本)
一、新建api文件夹 在项目目录下创建api文件夹,内放files跟index.js文件夹,files文件夹内放每个页面对应的js请求接口 1、index.js /*** api接口的统一出口*/ const api {}; const requireComponent require.context(./files, false, /\.js$/) requi…...

格式化后数据恢复,教你3个实用方法!
“格式化后数据还能恢复吗?前几天因为我的电脑中了病毒,我不得不将它进行格式化操作。但是我电脑里有很多比较重要的文件,有什么方法可以帮我恢复电脑中的文件吗?求解答!” 格式化是一种比较常见的数据清除方法&#x…...

LaTex使用技巧21:设置中文环境、字体、行间距和页边距
我在Overleaf上编写我的中文LaTex,设置了中文环境,字体、行间距以及页间距,记录一下方便以后查询。 使用中文环境命令为: \usepackage{xeCJK}可以使用Overleaf上支持的中文字体Fonts for CJK Chinese,设置字体的命令…...

【RabbitMQ】golang客户端教程3——发布订阅(使用fanout交换器)
发布订阅 在上一个教程中,我们创建了一个工作队列。工作队列背后的假设是每个任务只传递给一个工人。在这一部分中,我们将做一些完全不同的事情——我们将向多个消费者传递一个消息。这就是所谓的“订阅/发布模式”。 为了说明这种模式,我们…...

图像处理学习笔记
图像处理的流程:获取图像-分割区域-特征提取。 嵌入式工业读码器 :包括DM码、QR码、vericode码 Blob分析与形态学 1.Blob区域是Blobs这一数据类型在halcon中的一种贴切的表达形式。 采集图像-区域分割,最后通过特征(如圆度、面积、…...

87端口无法访问-GoogleChrome非安全端口列表
以下为Google Chrome 默认非安全端口列表 平时我们服务器尽量不要开启这些端口,会产生访问不了的错误! 1, // tcpmux7, // echo9, // discard11, // systat13, // daytime15, // netstat17, // qotd19, // chargen20, // ftp data…...

pyautogui 配合 selenium 实现桌面坐标系定位元素坐标,模拟真实鼠标行为
pyautogui 配合 selenium 实现桌面坐标系定位元素坐标,模拟真实鼠标行为。 场景:当我需要点击某个元素,或者触发浏览器的自动填充账号密码时,自动化点击无效。但是想要模拟真实鼠标点击又需要元素的坐标通过pyautogui来实现。通过…...

c#设计模式-创建型模式 之 工厂模式
前言: 工厂模式(Factory Pattern)是一种常用的对象创建型设计模式。该模式的主要思想是提供一个创建对象的接口(也可以是抽象类、静态方法等),将实际创建对象的工作推迟到子类中进行。这样一来,…...

Photoshop 2023 25.0beta「Mac」
Photoshop 2023是一款专业图像处理软件,它主要用于图像编辑、合成和设计等方面。 Photoshop beta创新式填充的功能特色包括: 自动识别和删除对象:该功能可以自动识别图像中的对象,并用周围的图像填充空白部分,使图像看…...

机器学习基础07-模型选择01-利用scikit-learn 基于Pima 数据集对LogisticRegression算法进行评估
选择合适的模型是机器学习和深度学习中非常重要的一步,它直接影响到模型的性能和泛化能力。 “所有模型都是坏的,但有些模型是有用的”。建立模型之后就要去评 估模型,确定模型是否有用。模型评估是模型开发过程中不可或缺的一部 分ÿ…...

单片机实现动态内存管理
1.简介 多数传统的单片机并没有动态内存管理功能。单片机通常具有有限的存储资源,包括固定大小的静态RAM(SRAM)用于数据存储和寄存器用于特定功能。这些资源在编译时被分配并且在程序的整个生命周期中保持不变。 2.动态内存管理好处 灵活性和…...

(JS逆向专栏十一)某融平台网站登入RSA
声明: 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 名称:点融 目标:登入参数 加密类型:RSA 目标网址:https://www.dianrong.com/accoun…...

c++ boost circular_buffer
boost库中的 circular_buffer顾名思义是一个循环缓冲器,其 capcity是固定的当容量满了以后,插入一个元素时,会在容器的开头或结尾处删除一个元素。 circular_buffer为了效率考虑,使用了连续内存块保存元素 使用固定内存&#x…...

网络编程——端口
端口 一、端口概述 TCP/IP 协议采用端口标识通信的进程 用于区分一个系统里的多个进程 二、端口特点 1、对于同一个端口,在本同系统中对应着不同的进程 2、对于同一个系统,一个端口只能被一个进程拥有 3、一个进程拥有一个端口后,传输层送…...

【网络】自定义协议 | 序列化和反序列化 | Jsoncpp
本文首发于 慕雪的寒舍 以tcpServer的计算器服务为例,实现用jsoncpp来进行序列化和反序列化 阅读本文之前,请先阅读 自定义协议 | 序列化和反序列化 | 以tcpServer为例 1.安装jsoncpp 我所用的系统是centos7.6,先用下面的命令查找相关的包 …...

PHP实践:用openssl打造安全可靠的API签名验证系统
🏆作者简介,黑夜开发者,全栈领域新星创作者✌,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已…...

每天一道leetcode:剑指 Offer 50. 第一个只出现一次的字符(适合初学者)
今日份题目: 在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。 示例1 输入:s "abaccdeff" 输出:b 示例2 输入:s "" 输出: 提示 0 …...

【第五章 flutter学习之flutter进阶组件-下篇】
文章目录 一、Scaffold属性二、TabBar三、路由四、AlertDialog、SimpleDialog、showM...五、PageView六、Key七、AnimatedList八、动画 一、Scaffold属性 Flutter Scaffold 是一个用于构建基本用户界面的布局组件。它提供了许多属性,使得开发者能够轻松地创建一个完…...

单元测试和集成测试有什么区别
单元测试和集成测试有什么区别 单元测试和集成测试是软件开发中的两个重要测试阶段,它们的主要区别如下: 目的: 单元测试:主要针对代码的最小可测试单元,通常是一个函数或方法,确保它按照预期工作。集成…...

如何实现基于场景的接口自动化测试用例?
自动化本身是为了提高工作效率,不论选择何种框架,何种开发语言,我们最终想实现的效果,就是让大家用最少的代码,最小的投入,完成自动化测试的工作。 基于这个想法,我们的接口自动化测试思路如下…...

SAP 开发编辑界面-关闭助手
打开关闭助手时的开发界面如下: 关闭关闭助手后的界面如下: 菜单栏: 编辑--》修改操作--》关闭助手...

【el-image图片查看时 样式穿透表格问题】
element-ui el-image图片查看 样式混乱 解决方式 ::v-deep(.el-table__cell) {position: static !important; // 解决el-image 和 el-table冲突层级冲突问题 }加个样式即可...

GPT带我学-设计模式-模板模式
1 请你给我介绍一下设计模式中的模板模式 模板模式是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的具体实现延迟到子类中。模板模式允许子类重新定义算法的某些特定步骤,而不需要改变算法的结构。 模板模式由以下几个角色组成&…...

Windows下调试UEFI程序:Visual Studio调试
以edk2\MdeModulePkg\Application\HelloWorld这个项目作为调试目标。 1. 使用VS2017建立Makefile工程 VS2017, 新建 project,取名X64dbg_vs。 Visual C > Other > Makefile Project, 注意项目路径为HelloWord程序路径。 随便填写config中的字符串ÿ…...

Vue中监听路由参数变化的几种方式
目录 一. 路由监听方式: 通过 watch 进行监听 1. 监听路由从哪儿来到哪儿去 2. 监听路由变化获取新老路由信息 3. 监听路由变化触发方法 4. 监听路由的 path 变化 5. 监听路由的 path 变化, 使用handler函数 6. 监听路由的 path 变化,触发method…...