Mysql中事务的读一致性问题,以及如何用MVCC解决

事务四大特性的实现:

原子性事务具有回滚的能力,InnoDB引擎使用undo log日志表来进行回滚操作。

持久性InnoDB引擎使用redo log日志表来保证数据的持久性。

事务的隔离性产生的问题:

**脏读:**一个事务读取到了另一个事务未提交的数据。

**不可重复读:**一个事务读取到了另一个事务已提交的数据,在同一个事务内,不管进行多少次查询,查询到的结果都是相同的。

**虚读(幻读):**一个事务读取了另一个事务提交的新增数据。

事务并发的三大问题其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。

mysql数据库的隔离级别:

Read Uncommitted (读未提交),未解决任何并发问题,事务未提交的数据对其他事务也是可见的,会出现脏读。

Read Committed (已提交读),解决脏读问题,一个事务开始之后,只能看到已提交的事务所做的修改,会出现不可重复读。

Repeatable Read (可重复读),解决不可重复读问题,在同一个事务中多次读取同样的数据结果是一样的,这种隔离级别未定义解决幻读的问题。

Serializable (串行化),解决所有问题,最高的隔离级别,通过强制事务的串行执行。

InnoDB对事务隔离级别的支持程度:

|-----------------------------|-----|-------|------------|
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
| Read Uncommitted (读未提交) | 可能 | 可能 | 可能 |
| Read Committed (已提交读) | 不可能 | 可能 | 可能 |
| Repeatable Read (可重复读) | 不可能 | 不可能 | 对InnoDB不可能 |
| Serializable (串行化) | 不可能 | 不可能 | 不可能 |

**思考:**如果要解决读一致性的问题,保证一个事务中前后两次读取数据结果一致,实现事务隔离,应该怎么做?

**第一种解决方式:**在读取数据前,对其加锁,阻止其他事务对数据进行修改

(LBCC) Lock BasedConcurrency Control

**第二种解决方式:**生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取

(MVCC) Multi VersionConcurrency Control。MVCC只在RC RR中使用。

MVCC解决读一致性问题原理:

测试使用的环境:mysql数据,采用引擎InnoDB,采用隔离级别Repeatable Read (可重复读)。

MVCC的概念:

(MVCC) Multi VersionConcurrency Control。MVCC只在ReadCommitted (已提交读)和Repeatable Read (可重复读)中使用。

MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。

一句话讲,MVCC就是用 同一份数据临时保留多版本的方式 的方式,实现并发控制。

Mysql会在表中添加2个隐藏的字段,DB_TRX_ID(插入或者更新行的最后一个事务的ID) 和 DB_ROLL_PTR (回滚指针)。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。回滚指针用来查找历史版本的数据。

准备环境 | MVCC效果演示:

创建表结构,添加数据

sql 复制代码
CREATE TABLE `t_mvcc` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

添加数据后如下:

创建测试表,用来生成事务ID的作用:

sql 复制代码
CREATE TABLE `t_mvcc_demo`(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

数据如下:

MVCC 识别规则

当执行查询sq|时会生成一致性视图read-view,它由执行查询时所有未提交事务id数组(数组里最小的id为min id)和已创建的最大事务id (max id)组成,查询的数据结果需要跟read-view做比对从而得到快照结果。

版本链比对规则:

1.如果落在绿色部分( trx jid<min. id),表示这个版本是已提交的事务生成的,这个数据是可见的;

2.如果落在红色部分( trx id>max. id),表示这个版本是由将来启动的事务生成的,是肯定不可见的;

3.如果落在黄色部分(min. id <=tnx id<=max_ id),那就包括两种情况

a.若row的trx_ id在数组中,表示这个版本是由还没提交的事务生成的,可见,当前自己的事务是可见的;

b.若row的trx. id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

图解

相关推荐
运维行者_5 小时前
企业无线网络监控的挑战与智能化演进趋势
大数据·运维·服务器·网络·数据库
国强_dev6 小时前
技术探讨:使用 stunnel 加密转发数据库连接时,如何获取客户端真实 IP?
数据库·网络协议·tcp/ip
@insist1236 小时前
系统规划与管理师-信息系统规划核心工作要点解析
数据库·软考·系统规划与管理师·软件水平考试·系统规划与管理工程师
超级数据查看器6 小时前
超级数据查看器 v10.0 发布
java·大数据·数据库·sqlite·安卓
数安3000天7 小时前
增量数据如何自动分类分级,避免目录“过期“?
大数据·数据库
南墙上的石头8 小时前
麒麟 V10 重装人大金仓 V8R6 踩坑实录(含 MySQL 兼容模式)
数据库·mysql
画中有画9 小时前
论向量数据库在项目中的应用
数据库
spider_xcxc9 小时前
Redis 数据库高质量实践指南(一)
运维·数据库·redis·oracle·云计算
l1t10 小时前
在linux和windows中解决duckdb 1.6dev版本输出执行计划报错问题
linux·运维·数据库·windows·duckdb
执子手 吹散苍茫茫烟波10 小时前
RC 隔离级别下 MySQL InnoDB 死锁典型案例
数据库·mysql