一、事务完整性问题

脏读:可以读取其他事务未提交的数据,如果该事务回滚,则数据为错误数据。

不可重复读:A事务查看,B事务修改提交,A事务再次查看,数据不一样。

幻读:幻读与不可重复读相似,但不可重复读重点在于update和delete,幻读重点在于insert

t Session A                   Session B
|
| START TRANSACTION;          START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| empty set
|                             INSERT INTO t_bitfly
|                             VALUES (1, 'a');
|
| SELECT * FROM t_bitfly;
| empty set
|                             COMMIT;
|
| SELECT * FROM t_bitfly;
| empty set
|
| INSERT INTO t_bitfly VALUES (1, 'a');
| ERROR 1062 (23000):
| Duplicate entry '1' for key 1
v (???刚刚明明告诉我没有这条记录的)
t Session A                  Session B
|
| START TRANSACTION;         START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                            INSERT INTO t_bitfly
|                            VALUES (2, 'b');
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                            COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|
| UPDATE t_bitfly SET value='z';
| Rows matched: 2  Changed: 2  Warnings: 0
| (怎么多出来一行)
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | z     |
| |    2 | z     |
| +------+-------+
|

二、事务隔离级别

1. 读未提交(Read Uncommitted)

原理:任何操作都不加锁

2. 读提交(Read Commit)

原理:读操作不加锁,写操作加锁。读被加锁的数据时,读事务每次都读undo log中的最近版本,因此可能对同一数据读到不同的版本(不可重复读),但能保证每次都读到最新的数据。

3. 可重复读(Reapable Read)

原理:第一次读数据的时候就将数据加行锁(共享锁),使其他事务不能修改当前数据,即可实现可重复读。但是不能锁住insert进来的新的数据,当前事务读取或者修改的同时,另一个事务还是可以insert提交,造成幻读。

4. 串行化(Serializable)

原理:锁表,读锁和写锁阻塞。

三、InnoDB事务相关概念

●  当前读

读取记录的最新版本,读取时要保证其他事务不能不能修改该记录,通常对该记录加锁实现。

如:select ... lock in share mode;      lock table table_name read;   -- 共享锁(并发时可以继续加锁)

select ... for update;    insert .....;    update ...;   delete ...;   -- 排他锁(并发时只有一个事务持有锁)

●  快照读

非阻塞读,如非串行隔离级别的select(串行隔离级别下select退化为当前读)。该设计可以实现读-写不冲突,也减少了行锁使用,降低了开销。它的实现基于多版本并发控制,即MVCC。

●  redo log

MySQL在开启事务时,会将执行的SQL保存到指定的log文件,即redo log。当MySQL执行recovery时执行redo log里的SQL操作即可。redo log不会被立即写入磁盘,会先写入redo buffer;当客户端执行commit时,redo buffer的内容会视情况存入磁盘。

●  undo log

与redo log相反,undo log是为了回滚事务而写的日志,具体内容就是copy事务开始前的数据(行)到undo buffer。

undo log分为两种:

insert undo log:执行insert新记录时产生,只在回滚是用到,提交事务后可以立即丢弃;

update undo log:执行update/delete时产生,不仅在回滚时用到,在快照读时也需要,所以不能随意丢弃。只有在快照读或事物回滚不涉及该日志时,才会被purge线程统一清除。它对MVCC有着实质性的帮助。

与redo buffer一样,undo buffer也是环形缓冲,当缓冲满的时候buffer内容会被刷新到磁盘。

与redo log不同的是,undo log没有独立的磁盘文件,所有的undo log均被存在主ibd数据文件中(表空间)。

四、MVCC

MVCC,Mult-Version-Concurreny-Control,多版本并发控制,是数据库控制并发访问的一种手段,在mysql,oracle,PostgreSQL中都有应用。

通常只有在读提交可重复读的隔离级别才会应用该模式。

在MySql中是在InnoDB的引擎级别实现的。

1. MVCC的作用:

  • 不加锁的情况下处理读写冲突(读的时候不阻塞写,写的时候不阻塞读),提高访问性能,减少开销。
  • 解决脏读、幻读、不可重复读等问题,但不能解决更新丢失问题(并发写)。

2. MVCC的实现:三个隐式字段+版本链(undo log)+一致性视图(Read View)

(1)Innodb隐式字段

  • DB_TRX_ID:6byte,存储修改了此数据行的事务id,当事务对数据做了修改操作(insert/update/delete)后,才会为其分配唯一的DB_TRX_ID。DB_TRX_ID是自增的。
  • DB_ROLL_POINTER:7byte,回滚指针,用于配合undo long,指向上一个版本(存储于rollback segment)。
  • DB_ROW_ID:6byte,当表没有主键,并且没有不允许为null的唯一索引时,InnoDB会以DB_ROW_ID创建聚簇索引。

purge线程:

InnoDB的版本记录还有个隐式标志位字段(deleted_bit),用来标记记录是否被删除。为了实现MVCC机制,update/delete都不会直接删除老的版本,而且设置一下老版本的deleted_bit。

为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit = true的版本记录。

又为了不影响MVCC的正常工作,purge线程也维护了一个自己的Read View(这个Read View相当于系统中最老活跃事务的Read View)。如果一版本记录deleted_flag = true,并且BD_TRX_ID相对于purge线程的Read View可见,那么这条记录一定是可以被安全清除的。

(2)版本链

版本链是一种链表,由数据行的修改记录构成,由数据行的聚簇索引包含的两个隐藏字段(DB_TRX_ID, DB_ROLL_POINTER)连接。

select * from t_user;

name age DB_ROW_ID DB_TRX_ID DB_ROLL_POINTER
a 1 1 null null

update t_user set name = 'b';

第一步:开启事务1,对记录加排它锁;

第二步:拷贝记录到undo log,作为一个旧版本;

第三步:修改行数据name 'a' ->'b'; 修改隐式字段事务id为当前事务1的id;回滚指针指向undo log的版本记录;

第四步:提交事务,释放锁。

update t_user set age = 2 ;

第一步:开启事务2,对记录加排它锁;

第二步:拷贝记录到undo log,发现该记录已经有undo log了,DB_TRX_ID=1的undo log就成了版本链表的表头;

第三步:修改行数据age 1 ->2; 修改隐式字段事务id为当前事务2的id;回滚指针指向事务1创建的的版本记录;

第三步:提交事务,释放锁。

可以看出,版本链是由不同事务修改同一记录而产生的undo log链表,链首是最新的版本,链尾是最老版本。

上面讲purge线程的时候提到过,版本记录不被用到时会被purge线程清除,事务1提交后DB_TRX_ID=1的线程可能已经被清除了,所以链表也不一定能够形成。

(3)一致性视图(Read View)

当某行数据存在版本链时去读取它,应该读取哪个版本呢?

开启事务后,执行快照读的那一刻,会生成当前数据库系统的一个快照(RC和RR的生成时机不一样,RC下每次select都会生成,RR只在第一次select生成,这是两种隔离级别的主要区别),记录并维护此时活跃的所有的事务id(DB_TRX_ID),这个快照就是Read View。

一致性视图主要用于版本可见性判断。

InnoDB会比较当前事务的DB_TRX_ID与Read View里维护的DB_TRX_ID。

trx_ids: 生成Read View时,当前活跃的事务id列表;

min_trx_id: trx_ids的最小值;

max_trx_id: trx_ids的最大值+1;

creator_trx_id: 生成该事务的事务id(单开启事务是没有事务id的,默认为0,creator_trx_id为0)。

版本链中的某个版本是否可以被当前事务可见,根据如下情况判断:

  • 当trx_id = creator_trx_id时,当前事务可以看到自己修改的数据,可见;
  • 当trx_id < min_trx_id时,生成此数据(版本链)的事务已经提交了,可见;
  • 当trx_id > max_trx_id时,表明生成此数据的事务是在生成此Read View后才开启的,不可见;
  • 当min_trx_id < trx_id < max_trx_id时,
  1. trx_id在trx_ids里面,说明生成当前Read View时,活跃事务还未提交,不可见;
  2. trx_id不在trx_ids里面,说明事务在生产当前Read Veiw时已经提交了,可见。

不可见时,就要顺着版本链找下一个版本。

MySQL事务隔离级别以及实现原理相关推荐

  1. mysql事务隔离级别及实现原理

    mysql事务 Markdown编辑器用的不顺手,自己选的,跪着也要用完.        事务通俗的来讲就是SQL要么全部执行成功,要么全部执行失败回滚到执行前的状态.不存在部分执行成功,部分执行失败 ...

  2. MySQL事务隔离级别和实现原理

    经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢?本文就帮大家梳理一下. MySQL 事务 本文所说的 MySQL 事务都是指在 I ...

  3. 一文讲清楚MySQL事务隔离级别和实现原理,后台开发人员必备知识

    经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢?本文就帮大家梳理一下. MySQL 事务 本文所说的 MySQL 事务都是指在 I ...

  4. mysql事务隔离级别之锁实现原理,脏读、不可重复读、幻读出现原因及解决方案

    mysql事务隔离级别原理 观看了很多网上的博客,挺令人伤心,很难找到想要的答案... 一:所需知识 1,mysql中的锁 1.1,读锁(共享锁) 规则:若事务1对数据对象A加上读锁,则事务1只能读A ...

  5. mysql 事务隔离级别实现原理_MySQL事务隔离级别和实现原理 - 米扑博客

    开发中经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗, 事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢? MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引 ...

  6. 5、MySQL事务隔离级别详解

    事务的隔离性就是指当多个事务同时运行时,各事务之间相互隔离,不可互相干扰.如果事务没有隔离性,就容易出现脏读.不可重复读和幻读等情况. 为了保证并发时操作数据的正确性,数据库都会有事务隔离级别的概念. ...

  7. Mysql事务隔离级别及MVCC(多版本并发控制)

    一.MySQL事务隔离级别 先注明一点:以下讨论都是在多事务并发的情境下讨论的 事务的特性(InnoDB引擎才有事务): ACID 原子性:一个事务不可再分割,要么都执行要么都不执行 一致性:一个事务 ...

  8. mysql 事务 隔离级别_MySQL的四种事务隔离级别

    https://www.cnblogs.com/huanongying/p/7021555.html 本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的 ...

  9. mysql事务隔离级别 花_mysql事务隔离级别

    很多PHP开发者在面试的时候遇到这个问题都会卡壳.这是因为理解得不够透彻,今天让我带领大家梳理一下mysql事务隔离级别 数据库有四种隔离级别,分别是Read uncommitted,Read com ...

最新文章

  1. 深度有趣 | 06 变分自编码器
  2. 共享资源的保护:锁机制
  3. 三、MySql查询语句执行的特征
  4. XCTF-高手进阶区:Web_php_include
  5. 求字典key的和python_python怎么将字典key相同的value值, 合并
  6. Xcode 静态库调试策略
  7. 03-14 设备交互 API
  8. 【汇编语言与计算机系统结构笔记20】补充内容:可定制处理器指令集
  9. matlab2c使用c++实现matlab函数系列教程-perms函数
  10. 软件测试综合笔试题目及参考答案
  11. Koa2 之文件上传下载
  12. abaqus Isight学习
  13. 怎么把短视频做成表情包?短视频制作gif只需三步
  14. 3小时快学期权(第二版)读书笔记(上)
  15. 【考研英语】词汇积累(详细全面,2023最新版)
  16. 心情手札——光头日记
  17. Part 1 ——ActiveMQ 概述
  18. Ubuntu20.04LTS 安装QQ 微信 钉钉 最简单,最好用的方式!
  19. 大华 / 海康威视(HIKVISION) 网络视像头的连接及使用
  20. Windows系统提示“telnet不是内部或外部命令,也不是可运行的程序或批处理文件”怎么办

热门文章

  1. 会计日常用语英语词汇
  2. phpstudy本地环境搭建图文教程
  3. 创业心得--国产化图形引擎
  4. 开启工作负载管理失败的问题|Failed to enable workload management
  5. Session原理,生命周期
  6. Dictionary与KeyValuePair的区别
  7. 网络打不其他计算机的共享文件,局域网共享文件夹无法被其它电脑访问怎么办...
  8. QLExpress基本语法
  9. 竞选计算机课代表演讲稿开头,竞选课代表演讲稿
  10. 初创企业重新设计管理系统租用方案:添加ARM处理资源并将云计算作为主脑