MySQL 中的 MVCC 版本控制机制原理
1. MVCC(多版本并发控制)概述
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库事务并发控制机制,主要用于提高数据库的读写性能。它通过维护数据的多个版本,使得读操作无需加锁,同时保证一致性,减少了事务之间的阻塞。
在 MySQL 的 InnoDB 存储引擎中,MVCC 主要用于**可重复读(REPEATABLE READ)和读已提交(READ COMMITTED)**这两种事务隔离级别。
2. MVCC 的实现原理
MVCC 通过隐藏删除和修改的行,加上一些额外的信息来实现多版本控制。主要依赖于 UNDO日志 和 事务 ID(Transaction ID)。
(1) 数据隐藏 & 版本控制
InnoDB 的数据行结构中包含两个隐藏的字段:
trx_id(事务 ID):表示最近对该行进行修改的事务 ID。roll_pointer(回滚指针):指向该行的 旧版本(即 undo log 记录),从而支持回滚和版本链。
当数据被修改时:
- 更新(UPDATE):不会直接修改数据,而是将旧版本保存到
undo log,然后生成新的数据版本,并更新trx_id。 - 删除(DELETE):不会立即删除,而是生成一个新版本,标记该行已删除,并记录
undo log。 - 插入(INSERT):只插入最新版本的数据,不会产生历史版本(因此插入数据不受 MVCC 影响)。
(2) Undo Log 及回滚指针
Undo Log 主要用于:
- 回滚事务:当事务失败或回滚时,可以通过 Undo Log 恢复数据。
- MVCC 读取旧版本数据:Undo Log 形成一个版本链,事务可以基于
trx_id获取合适的旧版本数据,而不会影响其他事务。
(3) MVCC 的可见性规则
当一个事务读取数据时,它需要判断哪些数据版本对自己可见。InnoDB 通过 Read View(读取视图)来管理可见性。
可见性规则如下:
- 当前事务 ID (
trx_id) < Read View 的最小活跃事务 ID (min_trx_id):- 该数据版本已经提交,对当前事务可见。
- 当前事务 ID (
trx_id) > Read View 的最大活跃事务 ID (max_trx_id):- 该数据版本是在当前事务之后创建的,不可见。
- 当前事务 ID (
trx_id) 介于min_trx_id和max_trx_id之间:- 若
trx_id属于活跃事务列表,则表示该事务还未提交,不可见。 - 若
trx_id不在活跃事务列表中,则可见。
- 若
3. MVCC 在不同事务隔离级别下的表现
| 隔离级别 | MVCC 读取的版本 |
|---|---|
| 读已提交(Read Committed) | 每次 SELECT 都创建新的 Read View,读取最近提交的数据版本 |
| 可重复读(Repeatable Read) | 事务开始时创建 Read View,整个事务期间保持一致 |
| 串行化(Serializable) | 不使用 MVCC,需要加锁 |
未提交读(Read Uncommitted) 不使用 MVCC,而是直接读取最新的数据版本,因此可能会读取到未提交的数据(脏读)。
4. MVCC 的优缺点
优点
- 非阻塞读:读取数据不需要加锁,提高并发性能。
- 减少事务冲突:多个事务可以同时操作不同版本的数据,避免不必要的锁竞争。
- 提高可重复读性能:避免了
SELECT过程中加锁的开销。
缺点
- 需要额外存储:Undo Log 需要存储多个版本的数据,可能会导致存储空间增长。
- 版本回收问题:老版本数据需要定期清理,否则会影响性能。
- 不适用于高并发写入:因为写入仍然需要锁定行,多个事务同时写入相同数据时,仍然需要等待。
5. 总结
- MVCC 主要依赖
trx_id和undo log来维护数据的多个版本,允许事务在不同时间点读取合适的数据版本。 - 不同事务隔离级别下 MVCC 的行为不同,
Read Committed每次查询创建新 Read View,而Repeatable Read事务开始时创建 Read View 并保持不变。 - MVCC 使得大部分读操作无需加锁,提高了数据库的并发能力,但也带来存储开销和版本管理的挑战。
在实际应用中,MVCC 适用于读多写少的场景,对于高并发写入,可能需要结合锁机制或优化索引来提升性能。
理解 Read View 和 事务可见性规则
当事务在 READ COMMITTED 或 REPEATABLE READ 隔离级别下执行 SELECT 语句时,InnoDB 不会直接读取最新的数据版本,而是通过 Read View 来决定 哪个数据版本对当前事务可见。
Read View 的关键字段
在 MVCC 机制下,每个事务在读取数据时都会维护一个 Read View,它主要包含:
trx_id:每个事务都有一个唯一递增的事务 ID,越新的事务 ID 值越大。m_ids(活跃事务列表):当 Read View 生成时,当前正在执行但未提交的事务 ID 列表。min_trx_id(最小活跃事务 ID):m_ids中最小的事务 ID。max_trx_id(下一个将要分配的事务 ID):比当前所有活跃事务 ID 都大的值,代表未来新事务的起始 ID。
数据可见性规则
当事务 T 读取一行数据时,该数据的 trx_id(创建它的事务 ID)将与 T 的 Read View 进行比较,以决定该版本是否可见。
数据版本的 trx_id 与 Read View 比较 | 可见性 | 解释 |
|---|---|---|
trx_id < min_trx_id | ✅ 可见 | 该数据版本是比 Read View 生成时更早的事务创建的,并且该事务已经提交。 |
trx_id > max_trx_id | ❌ 不可见 | 该数据版本是比 Read View 生成时更晚的事务创建的,因此不可见。 |
min_trx_id ≤ trx_id < max_trx_id 且 trx_id ∈ m_ids | ❌ 不可见 | 该数据版本是由某个活跃未提交的事务创建的,不可见。 |
min_trx_id ≤ trx_id < max_trx_id 且 trx_id ∉ m_ids | ✅ 可见 | 该数据版本的事务已提交,但其事务 ID 仍然在 Read View 生成时的范围内,因此可见。 |
直观示例
假设有如下事务操作:
- T1 开启事务,写入数据 A,但未提交 (
trx_id = 10)。 - T2 开启事务,创建 Read View (
min_trx_id = 10, max_trx_id = 15)。 - T3 开启事务,并更新数据 A (
trx_id = 12),但也未提交。 - T4 开启事务 (
trx_id = 15),并提交更新数据 A 的事务。
此时:
- T2 读取数据 A 时,
trx_id = 10在m_ids内,未提交,不可见。 - T2 也看不到
trx_id = 12(未提交)。 - T2 只能看到
trx_id < 10的数据,即 T1 之前的版本。 - T4 提交后,T2 依然看不到
trx_id = 15创建的数据,因为 Read View 在创建时已经固定了事务状态。
如何理解 Read View 的作用
- 保证一致性:
- 在
REPEATABLE READ级别下,同一事务内多次SELECT看到的数据是一致的,因为 Read View 在事务开始时创建,不会变化。 - 在
READ COMMITTED级别下,每次SELECT都会生成新的 Read View,所以可以看到最新已提交的数据。
- 在
- 避免幻读:
REPEATABLE READ级别的 Read View 确保了事务期间看到的行数据不会随其他事务的提交而变化,但对INSERT仍然可能出现幻读(需借助Next-Key Lock解决)。
- 提升并发性能:
- 通过 Read View 让事务读取旧版本数据,而不需要加锁,避免阻塞其他事务。
创建 Read View
T1 开启事务时是否创建 Read View 取决于 事务的隔离级别 和 执行的 SQL 语句。
什么时候创建 Read View?
| 操作 | Read View 何时创建? |
|---|---|
READ COMMITTED | 每次执行 SELECT 语句时都会创建一个新的 Read View。 |
REPEATABLE READ | 第一次执行 SELECT 语句时 创建 Read View,并在整个事务生命周期内保持不变。 |
SERIALIZABLE | 由于需要加锁,不依赖 MVCC Read View,而是直接使用锁进行事务隔离。 |
T1 开启事务时是否创建 Read View?
- 如果 T1 只是执行
START TRANSACTION;,此时并不会创建 Read View,只是开启一个事务,还没有执行任何查询。 - 只有当 T1 执行
SELECT语句时,才会创建 Read View(前提是隔离级别需要 Read View,如READ COMMITTED或REPEATABLE READ)。 - 在
READ COMMITTED级别下,每次查询都会创建一个新的 Read View。 - 在
REPEATABLE READ级别下,T1 第一次查询时 会创建 Read View,后续查询都会使用这个 Read View,即使其他事务提交了新数据,T1 也不会看到(除非显式提交)。
除非显示提交的含义
这里的 “除非显式提交” 是指 T1 事务提交 (COMMIT) 后,再次开启新的事务并执行查询,此时会生成一个新的 Read View,从而看到其他事务提交的数据。
1. 提交事务的方式
在 MySQL 中,提交事务的方式主要有两种:
① 显式提交(Explicit Commit)
指 手动执行 COMMIT 语句 来提交事务:
BEGIN;
SELECT * FROM users; -- 事务 T1 创建 Read View
-- 此时 Read View 固定,无法看到其他事务提交的数据COMMIT; -- 显式提交事务
COMMIT之后,事务结束,Read View 被销毁。
如果 T1 之后再执行SELECT,需要开启新事务,此时会创建新的 Read View,可以看到最新数据。
② 隐式提交(Implicit Commit)
MySQL 在某些情况下会自动提交事务,比如执行以下 SQL 语句时:
- DDL 语句(
CREATE,ALTER,DROP,TRUNCATE) SET AUTOCOMMIT = 1(默认开启自动提交)LOCK TABLES(会自动提交当前事务)
示例:
BEGIN;
SELECT * FROM users; -- 创建 Read View
ALTER TABLE users ADD COLUMN age INT; -- DDL 语句触发隐式提交
SELECT * FROM users; -- 这时 Read View 重新创建
执行
ALTER TABLE之后,事务被 MySQL 隐式提交,Read View 也重新生成。
2. “除非显式提交” 的含义
在
REPEATABLE READ级别,T1 第一次查询时创建的 Read View 不会变化,即使其他事务 (T2) 提交了新数据,T1 也看不到。
只有当 T1 执行COMMIT之后,再次查询时才会创建新的 Read View,并看到最新数据。
(1) 事务 T1 只读取,不提交
-- 事务 T1 开启
BEGIN;
SELECT * FROM users; -- 创建 Read View (RV1)
此时 Read View (RV1) 记录了活跃事务列表。
-- 事务 T2 执行更新
BEGIN;
INSERT INTO users VALUES (2, 'Bob');
COMMIT;
事务 T2 提交了新数据。
-- T1 继续查询
SELECT * FROM users; -- 仍然使用 Read View (RV1),看不到 Bob
由于 T1 没有提交,它的 Read View 没变,所以看不到
T2提交的数据。
(2) T1 提交后,再次查询
COMMIT; -- 显式提交事务
BEGIN;
SELECT * FROM users; -- 重新创建 Read View (RV2)
T1 提交事务后,Read View (RV1) 销毁。
新事务创建新的 Read View (RV2),此时能看到 Bob!
3. 事务提交的不同方式总结
| 提交方式 | 触发时机 | 是否创建新 Read View |
|---|---|---|
显式提交 (COMMIT) | 事务手动提交 | ✅ 是,提交后开启新事务会创建新的 Read View |
隐式提交(DDL、LOCK TABLES 等) | 特定 SQL 语句执行时自动提交 | ✅ 是,事务自动提交,Read View 重新创建 |
未提交 (ROLLBACK 或未执行 COMMIT) | 事务未结束 | ❌ 否,事务继续使用旧的 Read View |
4. 结论
🔹 “除非显式提交” 的意思是:
- 在
REPEATABLE READ级别下,T1 不会看到其他事务的新提交数据,除非 T1 自己先COMMIT事务。 COMMIT之后,Read View 被销毁,新的查询会创建新的 Read View,这时就能看到最新数据了!
示例
假设数据库初始状态:
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice');
场景 1:REPEATABLE READ
-- T1 事务
BEGIN;
SELECT * FROM users; -- (此时创建 Read View)
这时 Read View 记录了当前活跃事务列表和
min_trx_id。
-- T2 事务
BEGIN;
INSERT INTO users VALUES (2, 'Bob');
COMMIT;
-- T1 继续查询
SELECT * FROM users; -- 仍然只能看到 Alice,因为 Read View 不变
T1 的 Read View 在事务开始时确定,不会看到
Bob。
场景 2:READ COMMITTED
-- T1 事务
BEGIN;
SELECT * FROM users; -- (此时创建 Read View)
Read View 记录了当前事务状态。
-- T2 事务
BEGIN;
INSERT INTO users VALUES (2, 'Bob');
COMMIT;
-- T1 再次查询
SELECT * FROM users; -- 这次能看到 Bob,因为 Read View 在每次查询时重新生成
READ COMMITTED级别每次查询都会创建新的 Read View,因此 T1 在第二次查询时能看到T2提交的数据。
Read View 绑定性
1. 事务只能看到自己创建的 Read View
- Read View 是事务内部的快照,用于决定当前事务能看到哪些数据版本。
- 不同事务的 Read View 互不影响,事务 A 无法访问事务 B 的 Read View。
- 每个事务只能使用自己创建的 Read View 来查询数据。
2. 示例:不同事务的 Read View 是独立的
-- 事务 A 开始
BEGIN;
SELECT * FROM users; -- 创建 Read View A
此时 Read View A 记录了当前活跃事务列表。
-- 事务 B 开始
BEGIN;
SELECT * FROM users; -- 创建 Read View B
此时 Read View B 也创建了,可能与 Read View A 不同。
-- 事务 A 继续查询
SELECT * FROM users; -- 仍然使用 Read View A
事务 A 只能使用自己的 Read View A,而不会使用事务 B 的 Read View。
-- 事务 B 继续查询
SELECT * FROM users; -- 仍然使用 Read View B
事务 B 只能使用自己的 Read View B,而不会使用事务 A 的 Read View。
所以,每个事务的 Read View 就像是自己专属的“数据时间快照”,它决定了事务能看到的数据版本 🎯。
默认事务
MySQL 默认是自动提交 (AUTOCOMMIT = 1),即每条 SQL 语句都会作为一个独立的事务执行,并在执行后立即提交。
- 在默认情况下,每条 SQL 语句(如
INSERT、UPDATE、DELETE)都会立即提交,不会等待COMMIT。 - 只有显式关闭
AUTOCOMMIT或使用BEGIN;/START TRANSACTION;才能开启手动提交模式。
示例 1:默认情况下,每条语句都会自动提交
SELECT @@AUTOCOMMIT; -- 查询当前自动提交模式
-- 结果:1 (表示自动提交开启)INSERT INTO users VALUES (1, 'Alice');
-- 这条 INSERT 语句在执行后立即提交,不需要手动 COMMIT。
如果想要手动管理事务(即不让 SQL 语句自动提交),可以通过以下两种方式:
方法 1:使用 SET AUTOCOMMIT = 0
SET AUTOCOMMIT = 0; -- 关闭自动提交
BEGIN; -- 开启事务
UPDATE users SET name = 'Bob' WHERE id = 1;
COMMIT; -- 手动提交事务
注意:
SET AUTOCOMMIT = 0的作用是对当前会话生效,也就是说,当前连接的所有操作都会使用手动提交,直到手动COMMIT或ROLLBACK。- 但是 如果连接断开,
AUTOCOMMIT也会恢复为默认值1。
方法 2:使用 START TRANSACTION; / BEGIN;
START TRANSACTION; -- 开启事务(不会立即提交)
UPDATE users SET name = 'Charlie' WHERE id = 1;
COMMIT; -- 手动提交事务
或者:
BEGIN; -- 也是开启事务
UPDATE users SET name = 'David' WHERE id = 1;
ROLLBACK; -- 撤销事务(如果不想提交)
区别:
START TRANSACTION;或BEGIN;只是针对当前事务关闭自动提交,并不会影响整个会话。- 当事务提交 (
COMMIT) 或回滚 (ROLLBACK) 后,自动提交模式 (AUTOCOMMIT=1) 仍然有效。
事务提交模式总结
| 方式 | 作用 | 影响范围 | 恢复方式 |
|---|---|---|---|
AUTOCOMMIT = 1(默认) | 每条 SQL 语句都会立即提交 | 整个会话(每个 SQL 语句) | 无需恢复 |
SET AUTOCOMMIT = 0 | 关闭自动提交,手动 COMMIT 事务 | 仅当前会话 | 连接断开后恢复为 1 |
START TRANSACTION; / BEGIN; | 仅当前事务手动提交 | 只影响当前事务 | COMMIT / ROLLBACK 后恢复自动提交 |
结论
✅ MySQL 默认是自动提交 (AUTOCOMMIT=1),每条 SQL 语句都会自动提交。
✅ 如果要手动管理事务,可以用 SET AUTOCOMMIT = 0 或 START TRANSACTION; / BEGIN;。
✅ 手动管理事务时,需要显式 COMMIT 或 ROLLBACK,否则事务可能会被锁住,影响并发性能。
如果想在事务中批量执行 SQL 并手动控制提交,建议使用 START TRANSACTION;,这样不会影响整个会话的自动提交行为! 🚀
MyBatis 默认行为
如果在 Java 代码中使用 MyBatis 执行 SQL 语句,而没有显式管理事务(比如没有调用 commit() 或 rollback()),那么默认情况下,MySQL 的 AUTOCOMMIT=1 会生效,每条 SQL 语句都会自动提交。
- MyBatis 不主动管理事务,而是依赖数据库的默认行为(自动提交)。
- 这意味着即使执行
INSERT、UPDATE、DELETE语句,也不需要显式COMMIT,数据会立即生效。
不手动管理事务(默认自动提交)
SqlSession sqlSession = sqlSessionFactory.openSession(); // 默认不手动控制事务
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.insertUser(new User(1, "Alice")); // 这条 SQL 立即提交
sqlSession.close(); // 关闭连接
这里的 insertUser() 方法执行后,SQL 语句会立即提交,因为 MySQL 默认是 AUTOCOMMIT=1。
如果想手动控制事务(比如执行多个 SQL 语句后统一提交),需要:
- 关闭自动提交(
openSession(false))。 - 手动
commit()或rollback()事务。
(2)手动管理事务
SqlSession sqlSession = sqlSessionFactory.openSession(false); // 关闭自动提交
try {UserMapper userMapper = sqlSession.getMapper(UserMapper.class);userMapper.insertUser(new User(2, "Bob"));userMapper.updateUser(new User(2, "Bob Updated"));sqlSession.commit(); // 统一提交事务
} catch (Exception e) {sqlSession.rollback(); // 发生异常则回滚
} finally {sqlSession.close(); // 关闭连接
}
这里 openSession(false) 关闭了自动提交,所以:
insertUser()和updateUser()不会立即提交。- 只有
sqlSession.commit()执行后,数据才会真正写入数据库。 - 如果发生异常,会执行
rollback(),撤销事务中的所有操作。
Spring + MyBatis 事务管理
在实际的 Spring 项目中,事务通常是由 Spring 事务管理器(@Transactional)来控制的,而不是手动调用 commit() 或 rollback()。
(3)使用 Spring 事务管理
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactional // 由 Spring 统一管理事务public void createUser() {userMapper.insertUser(new User(3, "Charlie"));userMapper.updateUser(new User(3, "Charlie Updated"));// 发生异常时,Spring 会自动回滚事务}
}
Spring 事务管理的特点:
@Transactional让 Spring 统一管理事务,默认是 非自动提交 的(AUTOCOMMIT=0)。- 方法执行成功时,Spring 自动提交 事务。
- 发生异常时,Spring 自动回滚 事务。
结论
✅ MyBatis 默认使用 MySQL 的 AUTOCOMMIT=1,每条 SQL 语句执行后都会自动提交。
✅ 如果需要手动管理事务,可以使用 openSession(false) 关闭自动提交,并手动 commit() 或 rollback()。
✅ 在 Spring 项目中,通常使用 @Transactional 让 Spring 统一管理事务,而不会直接调用 MyBatis 的 commit()。
所以,如果 MyBatis 代码里没有 commit(),而数据仍然成功写入数据库,那就是 MySQL 的自动提交功能在起作用! 🚀
SpringBoot 中的事务提交
在 Spring Boot 中,事务的提交方式主要取决于 是否使用了 Spring 事务管理(@Transactional),并不是单纯依赖 MySQL 的 AUTOCOMMIT=1。
1. Spring Boot 默认的事务行为
Spring Boot 默认不会自动提交事务,它的事务管理主要依赖于 Spring 事务管理器,而 Spring 事务管理默认是 AUTOCOMMIT=0(手动提交)。
在 Spring Boot 项目中,通常有两种情况:
- 没有
@Transactional(默认自动提交,每个 SQL 语句执行后都会立即提交,依赖 MySQLAUTOCOMMIT=1)。 - 使用
@Transactional(Spring 事务管理,事务方法结束后才会提交,默认AUTOCOMMIT=0)。
2. 如果没有 @Transactional,会使用 MySQL 自动提交
如果 没有 @Transactional,那么 MyBatis 或 JPA 在执行 SQL 语句时,都会立即提交事务,这时依赖 MySQL 的 AUTOCOMMIT=1。
3. 如果使用了 @Transactional,Spring 事务管理接管提交
🚀 在 @Transactional 作用下:
- Spring 事务管理会关闭 MySQL 自动提交 (
AUTOCOMMIT=0)。 - 所有 SQL 语句都会等到方法执行结束后才提交。
- 如果方法中抛出异常,Spring 会自动回滚事务,之前的 SQL 操作也不会生效。
4. 如何验证 Spring Boot 是否在使用事务?
可以在 application.properties 中查看 spring.datasource 配置:
spring.datasource.hikari.auto-commit=false # Hikari 数据源默认关闭自动提交
- 如果
auto-commit=false,那么即使没有@Transactional,数据库操作也不会立即提交,而是等待commit()。 - 如果
auto-commit=true,则默认会使用 MySQL 的AUTOCOMMIT=1,每条 SQL 执行后立即提交。
此外,还可以手动检查数据库的 AUTOCOMMIT 状态:
SELECT @@autocommit;
如果返回 1,说明 MySQL 处于自动提交模式,SQL 执行后会立即提交。
✅ 在 Spring Boot 代码中看不到 commit(),是因为 Spring 事务管理器帮我们自动管理了事务提交,而不是依赖 MySQL 自动提交。
Spring Boot 代码中不需要手动
commit(),并不一定是因为 MySQL 自动提交,而是 Spring 事务管理器负责了事务的提交和回滚! 🚀
相关文章:
MySQL 中的 MVCC 版本控制机制原理
1. MVCC(多版本并发控制)概述 MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库事务并发控制机制,主要用于提高数据库的读写性能。它通过维护数据的多个版本,使得读操作无…...
JWT认证服务
JSON Web Token(JWT)是一种用于在网络应用间安全地传递信息的紧凑、自包含的方式。以下是关于 JWT 认证服务器更详细的介绍,包括其意义、作用、工作原理、组成部分、时效性相关内容、搭建条件以及代码案例。 JWT 的意义与作用 意义…...
RAG中对于PDF复杂格式文件的预处理的解决方案:MinerU
RAG中对于PDF复杂格式文件的预处理的解决方案:MinerU 1. 场景 在RAG场景下,我们所遇到的文档格式可不仅仅局限于txt文件,而对于复杂的PDF文件,里面有图片格式的Excel、图片格式的文字、以及公式等等复杂的格式,我们很难用传统的方式去解析预处理成我们可以用的类似于TXT…...
手机中的type-C是如何防水的呢?
防水类型的type-C座子: 电子产品防水等级的区分: 这里的“IP”是国际防护标准等级;简而言之,IPXX中“XX”两位数字分别代表防尘和防水等级,其中防尘等级从0~6,防水等级则从0~8。 第…...
[Redis]Redis学习开篇概述
欢迎来到啾啾的博客🐱。 这是一个致力于构建完善 Java 程序员知识体系的博客📚。 它记录学习点滴,分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 引言 大家好…...
WordPress浮动广告插件+飘动效果客服插件
源码介绍 WordPress浮动广告插件飘动效果客服插件 将源码上传到wordpress的插件根目录下,解压,然后后台启用即可 截图 源码免费获取 WordPress浮动广告插件飘动效果客服插件...
Java基础关键_034_网络编程
目 录 一、概述 二、网络编程三要素 1.IP 地址 2.端口号 3.通信协议 (1)说明 (2)OSI 七层参考模型 (3)TCP/IP 四层参考模型 三、网络编程基础类 1.InetAddress 2.URL (1)…...
Ubuntu交叉编译器工具链安装
声明 本博客所记录的关于正点原子i.MX6ULL开发板的学习笔记,(内容参照正点原子I.MX6U嵌入式linux驱动开发指南,可在正点原子官方获取正点原子Linux开发板 — 正点原子资料下载中心 1.0.0 文档),旨在如实记录我在学校学…...
C# 操作 Redis
一、简介 C# 中通过 StackExchange.Redis 库可以方便地操作 Redis,实现高性能的数据缓存和存储。StackExchange.Redis 提供了强大的 API,允许开发者轻松连接、读取和写入 Redis 数据。通过使用 ConnectionMultiplexer 类,可以建立与 Redis 服…...
基于Python的招聘推荐数据可视化分析系统
【Python】基于Python的招聘推荐数据可视化分析系统(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 🚀🌟 基于Python的招聘推荐数据可视化分析系统!…...
光谱相机在工业中的应用
光谱相机(多光谱、高光谱、超光谱成像技术)在工业领域通过捕捉物质的光谱特征(反射、透射、辐射等),结合化学计量学与人工智能算法,为工业检测、质量控制和工艺优化提供高精度、非接触式的解决方案。以下是…...
Nginx介绍及使用
1.Nginx介绍 Nginx是一款开源的、高性能的HTTP和反向代理服务器 1.正向代理和反向代理 正向代理(代理客户端)是一种位于客户端和目标服务器之间的中间服务器。客户端通过正向代理服务器向目标服务器发送请求,代理服务器将请求转发给目标服…...
使用PyQt5绘制水波浪形的柱状显示流量—学习QTimer+QPainterPath
前言:进入学习Python开发上位机界面的第二阶段,学习如何开发自定义控件,从常用的控件入手学习,本期主要学习如何使用PyQt5绘制水波浪形的柱状显示流量。但是最后我放弃了,因为水波的效果达不到我想要的。 1. 明确想要…...
C++蓝桥杯实训篇(二)
片头 嗨咯~小伙伴们!今天我们来一起学习算法和贪心思维,准备好了吗?咱们开始咯! 第1题 数位排序 对于这道题,我们需要自己写一个排序算法,也就是自定义排序,按照数位从小到大进行排序。 举一…...
如何将本地更改的README文件同步到自己的GitHub项目仓库
如何将本地更改的 README 文件同步到 GitHub 仓库 在你 git clone 下来的工程目录下: 先使用 robocopy YOUR\SOURCE\CODE\DIR YOUR\GIT\CLONE\DIR /E /XD .git /DCOPY:T 将你的更改Copy到你git下来的工程中(上面的命令会自动处理,例如只会C…...
无人驾驶是自动化还是智能化?
这是一个由小米Su-7和人形机器人问题引起的思考:努力决定了下限,认知决定了上限。 一、无人驾驶既涉及自动化,也涉及智能化,这两者在无人驾驶系统中应该是相互融合、相辅相成的1、自动化(Automation) 自动化…...
实操(不可重入函数、volatile、SIGCHLD、线程)Linux
1 不可重入函数 为什么会导致节点丢失内存泄露?main函数在执行insert,但是没执行完就被信号中断了,又进了这个函数里,所以这个insert函数在不同的执行流中,同一个函数被重复进入,如果没有问题,…...
【Flask开发】嘿马文学web完整flask项目第2篇:2.用户认证,Json Web Token(JWT)【附代码文档】
教程总体简介:2. 目标 1.1产品与开发 1.2环境配置 1.3 运行方式 1.4目录说明 1.5数据库设计 2.用户认证 Json Web Token(JWT) 3.书架 4.1分类列表 5.搜索 5.3搜索-精准&高匹配&推荐 6.小说 6.4推荐-同类热门推荐 7.浏览记录 8.1配置-阅读偏好 8.配置 9.1项目…...
Ubuntu 下搭建 MCU 开发环境全流程指南(以 STM32 为例)
在嵌入式开发中,许多工程师都习惯于在 Windows 平台使用 Keil、IAR 等 IDE。然而,随着对自动化、可定制性以及开放工具链的需求增长,越来越多的开发者开始尝试在 Linux 环境下进行 MCU 开发。 本篇文章将以 STM32F1 系列 为例,手把手带你在 Ubuntu 下搭建一个完整的 MCU 开…...
Codecademy—— 交互式编程学习的乐园
一、网站概述 Codecademy 是一家美国在线学习编程知识的网站,它为编程学习者提供了一种全新的学习方式。在如今众多的编程学习平台中,Codecademy 凭借其独特的优势脱颖而出,吸引了全球数百万用户。其目标是帮助更多人轻松学习编程࿰…...
Python----计算机视觉处理(Opencv:道路检测之车道线拟合)
完整版: Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示) 一、获取左右车道线的原始位置 导入模块 import cv2 import numpy as np from matplot…...
OpenCV 图形API(13)用于执行两个矩阵(或图像)逐元素乘法操作的函数mul()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 描述 计算两个矩阵的每个元素的缩放乘积。 mul函数计算两个矩阵的逐元素乘积: dst ( I ) saturate ( scale ⋅ src1 ( I ) ⋅ src2 ( I ) ) …...
2025高频面试算法总结篇【二叉树】
文章目录 直接刷题链接直达非递归实现求二叉树的深度非递归从左至右打印一颗二叉树中的所有路径判断平衡二叉树二叉搜索树中第K小的元素二叉树的完全性检验根据前&中序遍历结果重建二叉树二叉树的最近公共祖先二叉树的直径二叉树的遍历 直接刷题链接直达 非递归实现求二叉…...
如何理解神经网络中的“分段线性单元”,优雅解析前向和反向传播
什么是非线性 非线性本质上指的是一个系统或函数中输入与输出之间的关系不呈现简单的比例关系,也就是说,输出不只是输入的线性组合 ( 比如 y k 1 x 1 k 2 x 2 b ) (比如yk1x1k2x2b) (比如yk1x1k2x2b)。下面详细解释这个概念: 缺乏叠加性…...
WVP-GB28181摄像头管理平台存在弱口令
免责声明:本号提供的网络安全信息仅供参考,不构成专业建议。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我联系,我将尽快处理并删除相关内容。 漏洞描述 攻击者可利用漏洞获取当前系统管…...
开源身份和访问管理方案之keycloak(三)keycloak健康检查(k8s)
文章目录 开源身份和访问管理方案之keycloak(三)keycloak健康检查启用运行状况检查 健康检查使用Kubernetes下健康检查Dockerfile 中 HEALTHCHECK 指令 健康检查Docker HEALTHCHECK 和 Kubernetes 探针 开源身份和访问管理方案之keycloak(三&…...
STM32看门狗原理与应用详解:独立看门狗 vs 窗口看门狗(上) | 零基础入门STM32第九十四步
主题内容教学目的/扩展视频看门狗什么是看门狗,原理分析,启动喂狗方法,读标志位。熟悉在程序里用看门狗。 师从洋桃电子,杜洋老师 📑文章目录 一、看门狗核心原理1.1 工作原理图解1.2 经典水桶比喻 二、STM32看门狗双雄…...
Android学习总结之service篇
引言 在 Android 开发里,Service 与 IntentService 是非常关键的组件,它们能够让应用在后台开展长时间运行的操作。不过,很多开发者仅仅停留在使用这两个组件的层面,对其内部的源码实现了解甚少。本文将深入剖析 Service 和 Inte…...
网络安全的挑战与防护策略
随着互联网的高速发展,人们的生活、学习和工作已离不开网络。然而,便利的背后也潜藏着巨大的安全隐患。从数据泄露、账户被盗,到网络攻击、系统瘫痪,网络安全问题层出不穷,影响范围从个人用户到国家机构。 网络安全&a…...
spring mvc异步请求 sse 大文件下载 断点续传下载Range
学习连接 异步Servlet3.0 Spring Boot 处理异步请求(DeferredResult 基础案例、DeferredResult 超时案例、DeferredResult 扩展案例、DeferredResult 方法汇总) spring.io mvc Asynchronous Requests 官网文档 spring.io webflux&webclient官网文…...
