当前位置: 首页 > news >正文

MySQL(174)如何理解MySQL的多版本并发控制(MVCC)?

MySQL的多版本并发控制(MVCC, Multi-Version Concurrency Control)是一种用于实现高并发性的机制,它允许多个事务同时读取和写入数据,而不会相互阻塞。MVCC主要在InnoDB存储引擎中实现,通过维护数据的多个版本来实现一致性和隔离性。

一、MVCC的基本原理

MVCC通过维护每行数据的多个版本,使得读操作不会阻塞写操作,写操作也不会阻塞读操作。它通过以下机制实现:

  1. 隐藏列

    • InnoDB表的每一行都有两个隐藏列:trx_idroll_pointer
    • trx_id(事务ID)记录了最近一次修改该行的事务ID。
    • roll_pointer指向回滚段中的上一个版本。
  2. 快照读

    • 快照读读取的是数据的某个版本快照,而不是当前最新版本。它通过检查每行数据的trx_id和当前事务的ID来决定读取哪个版本。
    • 快照读通常用于SELECT语句,不会加锁。
  3. 当前读

    • 当前读读取的是数据的最新版本,它会对读取的行加锁,确保数据的最新性和一致性。
    • 当前读通常用于SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE语句。

二、事务隔离级别与MVCC

MVCC在不同的事务隔离级别下有不同的表现:

  1. 读未提交(READ UNCOMMITTED)

    • 事务可以读取其他事务未提交的数据(脏读)。
    • 不适用MVCC。
  2. 读已提交(READ COMMITTED)

    • 事务只能读取其他事务已提交的数据。
    • 每次读取数据时,会读取最新的已提交版本。
  3. 可重复读(REPEATABLE READ)

    • 事务在开始时创建一个一致性视图,所有读取操作都基于这个视图。
    • 事务进行过程中,即使其他事务已提交,也不会看到这些修改。
    • 防止不可重复读和幻读。
  4. 序列化(SERIALIZABLE)

    • 最严格的隔离级别,事务完全串行化执行。
    • 会对读取的每一行数据加锁。

三、示例代码

以下是一些示例代码,展示了在不同隔离级别下,使用MVCC如何避免读写冲突。

1. 创建测试表并插入数据
CREATE TABLE test_mvcc (id INT PRIMARY KEY,value VARCHAR(50)
);INSERT INTO test_mvcc (id, value) VALUES (1, 'Initial Value');
2. 设置事务隔离级别并启动事务
-- 在会话1中(事务1)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;-- 在会话2中(事务2)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
3. 快照读示例
-- 在会话1中,读取数据
SELECT * FROM test_mvcc WHERE id = 1;-- 在会话2中,更新数据
UPDATE test_mvcc SET value = 'Updated Value' WHERE id = 1;-- 在会话1中,再次读取数据
SELECT * FROM test_mvcc WHERE id = 1;-- 此时,会话1中的两次读取结果都是 'Initial Value',因为使用的是快照读
4. 当前读示例
-- 在会话1中,使用当前读读取数据
SELECT * FROM test_mvcc WHERE id = 1 FOR UPDATE;-- 在会话2中,尝试更新数据
UPDATE test_mvcc SET value = 'Another Update' WHERE id = 1;-- 会话2中的更新操作会被阻塞,直到会话1提交或回滚事务
5. 提交事务
-- 在会话1中,提交事务
COMMIT;-- 在会话2中,更新操作解除阻塞,继续执行
UPDATE test_mvcc SET value = 'Another Update' WHERE id = 1;

四、Java代码示例

以下是一个Java示例程序,展示了如何通过JDBC设置事务隔离级别,并展示使用MVCC的效果。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class MVCCExample {private static final String JDBC_URL = "jdbc:mysql://localhost:3306/your_database";private static final String USER = "your_db_user";private static final String PASSWORD = "your_db_password";public static void main(String[] args) {try (Connection connection1 = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);Connection connection2 = DriverManager.getConnection(JDBC_URL, USER, PASSWORD)) {connection1.setAutoCommit(false);connection2.setAutoCommit(false);// 设置事务隔离级别为 REPEATABLE READconnection1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);connection2.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);// 在会话1中读取数据try (Statement statement1 = connection1.createStatement()) {ResultSet rs1 = statement1.executeQuery("SELECT value FROM test_mvcc WHERE id = 1");while (rs1.next()) {System.out.println("Session 1 - Initial Value: " + rs1.getString("value"));}}// 在会话2中更新数据try (Statement statement2 = connection2.createStatement()) {statement2.executeUpdate("UPDATE test_mvcc SET value = 'Updated Value' WHERE id = 1");}// 在会话1中再次读取数据try (Statement statement1 = connection1.createStatement()) {ResultSet rs1 = statement1.executeQuery("SELECT value FROM test_mvcc WHERE id = 1");while (rs1.next()) {System.out.println("Session 1 - After Update in Session 2: " + rs1.getString("value"));}}// 提交会话2connection2.commit();// 在会话1中再次读取数据(验证隔离级别的效果)try (Statement statement1 = connection1.createStatement()) {ResultSet rs1 = statement1.executeQuery("SELECT value FROM test_mvcc WHERE id = 1");while (rs1.next()) {System.out.println("Session 1 - After Commit in Session 2: " + rs1.getString("value"));}}// 提交会话1connection1.commit();} catch (SQLException e) {e.printStackTrace();}}
}

五、总结

MySQL的MVCC通过维护多个数据版本实现高并发性和一致性,使得读操作和写操作可以并行执行而不会互相阻塞。理解MVCC的工作原理,对于设计高性能、高并发的数据库应用至关重要。通过示例代码,我们可以看到在不同事务隔离级别下,MVCC如何帮助我们实现并发控制和数据一致性。

http://www.dtcms.com/a/311066.html

相关文章:

  • Spring框架与深度学习实战应用
  • 数字人开发02--前端服务配置
  • 【Java】不允许直接操作数据表中的数据,开发前台界面来实现对多个数据表的增删改查
  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第三天(JavaScript)
  • Python编程基础与实践:Python模块与包入门实践
  • MyBatisPlus之核心注解与配置
  • JP3-3-MyClub后台后端(三)
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘seaborn’问题
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要生成与智能检索优化进阶(377)
  • 2025-08 安卓开发面试拷打记录(面试题)
  • rabbitmq消息队列详述
  • 关于echarts的性能优化考虑
  • Pytorch-02数据集和数据加载器的基本原理和基本操作
  • Unity_数据持久化_XML基础
  • 【C++】第二十一节—一文详解 | 红黑树实现(规则+效率+结构+插入+查找+验证)
  • 福彩双色球第2025088期篮球号码分析
  • 电脑手机热点方式通信(上)
  • StarRocks vs ClickHouse:2025 年 OLAP 引擎终极对比指南
  • Day25-对称二叉树-
  • 仿真电路:(十七下)DC-DC升压压电路原理简单仿真
  • Clickhouse#记录隐藏字段
  • 综合:单臂路由+三层交换技术+telnet配置+DHCP
  • 【云计算】云主机的亲和性策略(四):云主机组
  • C 语言问题
  • 【机器学习】两大线性分类算法:逻辑回归与线性判别分析:找到分界线的艺术
  • 复杂路况下漏检率↓78%!陌讯动态决策模型在井盖缺失检测的实战解析
  • 系统性学习数据结构-第一讲-算法复杂度
  • Agents-SDK智能体开发[5]之集成MCP进阶
  • 机器学习 —— 决策树
  • [硬件电路-114]:模拟电路 - 信号处理电路 - 放大器的种类与比较