Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > Mysql事务底层原理

Mysql事务底层原理分析及说明

作者:龙门吹雪

这段文章详细解释了事务的概念、特性、使用方法和隔离级别,并重点介绍了MVCC机制及其在InnoDB存储引擎中的应用,文章还描述了事务的执行流程和背后的原理,帮助理解数据库在高并发场景下的数据一致性和完整性保障机制

一、事务的概念

事务(Transaction)就是由一组 SQL 语句构成的逻辑工作单元。它就像是一个不可分割的整体,要么里面的操作全部成功,要么全部失败,用于在高并发场景下保证数据的一致性和完整性。

二、事务的特性

三、事务的使用方法

在 MySQL 中,通常使用以下 SQL 语句来控制事务:

3.1 开启事务

-- 开启事务
start transaction;  -- 或者使用 begin;

3.2 执行一系列 SQL 操作

-- 执行一系列 sql 语句
select * from t where id > 1;
insert into t(a, b, c, d) values (3, 5, 5, 'beijing');

3.3 提交事务

-- 提交事务
commit;

3.4 回滚事务

-- 回滚事务
rollback;

注意:

MySQL 默认是 自动提交 (autocommit = 1) 模式。

这意味着你每执行一条 UPDATE 或 INSERT,它都会立即作为一个独立的事务提交。

如果要手动控制事务,必须先执行 START TRANSACTION 或将 autocommit 设为 0。

四、事务的隔离级别

MySQL InnoDB 存储引擎支持四种事务隔离级别:

1、读未提交(READ UNCOMMITTED):一个事务还没提交时,它做的变更就能够被其他事务看到。可能会产生脏读、不可重复读和幻读问题。

2、读已提交(READ COMMITTED):一个事务提交后,它做的变更才能被其他事务看到。

3、可重复读(REPEATABLE READ):MySQL的默认隔离级别。一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。

4、串行化(SERIALIZABLE):事务被强制串行执行,每个事务在执行时都会对其他事务影响的数据行进行加锁,从而避免并行访问。可以避免脏读、不可重复读和幻读问题,但并发性能最低。

查看和设置数据库的事务隔离级

-- 查看当前会话的隔离级别
select @@tx_isolation;

-- 查看全局的隔离级别
select @@global.tx_isolation;

-- 设置当前会话的事务隔离级别(设置全局隔离级别:将 SESSION 换为 GLOBAL)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

-- mysql8 查看当前会话的事务隔离级别
SELECT @@SESSION.TRANSACTION_ISOLATION;

-- mysql8 查看全局的事务隔离级别
select @@global.TRANSACTION_ISOLATION;

脏读:

不可重复读:

幻读:

4.1 读未提交

在这个级别下,一个事务可以读取到其他事务尚未提交(Commit)的修改。可能会产生脏读、不可重复读和幻读问题。

4.2 读已提交

一个事务提交后,其他事务才能看到变更的数据。读已提交隔离级别解决了脏读,但存在不可重复读、幻读现象。

4.3 可重复读

一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。该隔离级别可以解决脏读、不可重复读问题,但在特定场景下依然会存在幻读问题。

出现幻读的场景:

原因分析:

可重复读隔离级别下,会基于事务启动后第一次查询时建立的数据“快照”(Read View)来读取数据,它看不到其他事务在它之后插入或修改的任何数据。因此,在纯快照读的场景下,不会发生幻读。

但事务中存在如下 SQL 语句时,必须读取数据库中最新的、已提交的数据。为了保证数据一致性,它会忽略之前的快照,直接去读取当前数据库的最新状态。

上述例子中,T4 时刻,左边事务更新 id >  3 的记录,会忽略快照,而去数据库中查找最新的记录,从而查询到右边事务新增的记录,即更新了两条记录。

根据MVCC机制,修改的这两条记录的事务ID都会标记为左边事务的id,从而能在第三次查询中显示出来,即出现幻读。

解决方案:

在左边事务查询数据时增加读锁或写锁,阻止其他事务新增数据。

4.4 串行化

每个事务在执行时都会对其他事务影响的数据行进行加锁,从而避免并行访问。可以避免脏读、不可重复读和幻读问题,但并发性能最低。

五、事务的原理

5.1 核心概念

MVCC(Multi-Version Concurrency Control)多版本并发控制,通过保存数据的历史版本来实现并发控制,避免读写冲突,主要通过undo日志链来实现。

5.1.1 InnoDB 存储引擎的行格式

每次事务对行数据进行修改时,都会新生成一行记录,并且 DB_TRX_ID 保存该事务的ID,DB_ROLL_PTR 保存上一次修改该行记录的 undo log 位置指针

5.1.2 ReadView 快照

事务读取时创建的视图,包含:

快照的过滤规则:

MVCC 在读取每一行数据时,会检查该行的版本号(trx_id)是否对当前事务可见。判断逻辑如下:

5.2 事务执行流程

事务执行流程如下:

①查询处理:客户端发送 SQL 请求到 MySQL Server 层

②数据加载:如果所需数据页不在 Buffer Pool 中,从磁盘加载到内存

③事务开始:执行 START TRANSACTION,分配事务 ID 并创建 Read View

④数据修改:在 Buffer Pool 中创建新版本数据,原数据写入 Undo Log

⑤日志记录

两阶段提交

⑦后台刷新:脏页由后台线程异步刷入磁盘

事务执行的内存结构与磁盘文件示意图:

5.3 隔离级别与MVCC关系

MVCC 主要用于实现 READ COMMITTED(读已提交)和 REPEATABLE READ(可重复读)这两种隔离级别。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文