mysql事务超全~

大家好,我是程序媛雪儿,今儿咱聊聊mysql事务。

咱们先看一下什么是事务。

事务是什么

事务是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体向系统提交或者撤销操作,也就是说,这些操作要么同时成功,要么同时失败。

特性(ACID)

原子性(Atomicity):事务是不可分割的最小操作单元(要么都成功,要么都失败)

一致性(Consistency):事务完成时,必须使所有数据保持一致

隔离性(Isolation):数据库提供隔离机制,保证事务不受外部并发操作影响,在一个独立环境下运行

持久性(Durability):事务一旦提交或回滚,对数据库的改变是永久的,也就是说会保存到磁盘上

并发事务问题

有哪些

脏读

一个事务读到另外一个事务还没有提交的数据

事务A更新完数据还没提交,事务B此时读到了A还没提交的数据

不可重复读

一个事务先后读取同一条记录,但两次读取的数据不同

事务A第一次读到的是旧数据,第二次读这个数据前,这个数据已经被事务B改了,所以事务A第二次读到的数据和第一次读到的同一条数据不一样

幻读

一个事务按照条件查询数据的时候,没有对应的数据,但是在插入数据的时候,又发现这行数据已经存在了,好像出现了幻影

当事务A查数据库,发现id为1的数据没有,此时事务B把id为1的数据已经插入到数据库中,事务A再插入id为1的数据报错,再查id为1的数据,还是没有(因为解决了不可重复读,保证了两次数据一致)

解决方案

|----------|----|-------|----|
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
| 未提交读 | √ | √ | √ |
| 读已提交 | × | √ | √ |
| 可重复读(默认) | × | × | √ |
| 串行化 | × | × | × |

注:事务隔离级别越往下安全性越高,但是性能越差

事务的隔离级别是如何实现的?

本质还是老两套

锁:排他锁(一个事务获得了某一行,其他事务就不能再获取该行的锁了)

mvcc:多版本并发控制

什么是MVCC?

维护一个数据的多个版本,使得读写操作没有冲突

来看下面这个例子

MVCC的实现,主要依赖数据库记录中的隐式字段、undo log日志、readView

隐藏字段

|-------------|-------------------------|
| 隐藏字段 | 含义 |
| DB_TRX_ID | 最近修改事务ID,最后修改这条记录的事务ID |
| DB_ROLL_PTR | 回滚指针,指向是这条记录的上个版本 |
| DB_ROW_ID | 隐藏主键,表结构中如果没有主键就会生成这个字段 |

undo log日志中的版本链

事务对同一条记录修改,就会生成记录版本链,链表头部是最新的数据记录,尾部是最老的数据记录

readview

readview是快照读SQL执行时提取数据的依据。

这里聊到了一个概念,快照读,我们先搞明白什么是当前读和快照读

当前读:读取的是记录的最新版本,并且保证其他并发事务不能修改当前的记录(加锁)

快照读:读取的是记录数据的可见版本,可能是历史数据(不加锁、非阻塞)

|----------------|-----------------------------|
| 字段 | 含义 |
| m_ids | 当前活跃的事务ID集合(活跃的事务指的是未提交的事务) |
| min_trx_id | 最小活跃事务ID |
| max_trx_id | 最大事务ID+1 |
| creator_trx_id | 当前事务ID,readview创建的事务ID |

访问规则

trx_id代表的当前事务,在undo log日志当中,会依次遍历DB_TRX_ID,去找第一个符合的版本数据返回给用户

不同的隔离级别,生成的readview不同

read committed (读已提交):每次执行快照读时生成readview

事务5中查询id为30的记录,根据访问规则+生成的readview,第一次查询读到的是事务2,第二次查询读到的是事务3

repeatable read(可重复读):仅在事务第一次执行快照读时生成readview,后续复用该readview,保证在一个事务中读到的版本是一样的

事务5中查询id为30的记录,根据访问规则+生成的readview,第一次读到的是事务2,第二次查询读到的还是事务2,因为复用的第一个ReadView。

欢迎大家关注我的微信公众号,程序媛雪儿,雪儿会在上面发布编程的知识碎片,也有雪儿博客地址,上面有详细系统的笔记,雪儿是全栈,但是公众号目前主要还是发后端的技术,以后可能也会涉及到一些前端的知识,我们下期见,拜拜~

相关推荐
兜兜风d'28 分钟前
redis字符串命令
数据库·redis·缓存
忧郁的蛋~2 小时前
EFcore查询a表中符合b表列的值
数据库
xwz小王子2 小时前
ManipulationNet:开启真实世界机器人操作基准测试新时代
数据库·机器人
咯哦哦哦哦2 小时前
关于QT 打印中文 乱码问题
java·数据库·qt
野犬寒鸦2 小时前
从零起步学习Redis || 第十二章:Redis Cluster集群如何解决Redis单机模式的性能瓶颈及高可用分布式部署方案详解
java·数据库·redis·后端·缓存
ShooterJ3 小时前
Mysql小表驱动大表优化原理
数据库·后端·面试
程序员三明治3 小时前
【MyBatis从入门到入土】告别JDBC原始时代:零基础MyBatis极速上手指南
数据库·mysql·mybatis·jdbc·数据持久化·数据
cookqq3 小时前
MongoDB源码delete分析oplog:从删除链路到核心函数实现
数据结构·数据库·sql·mongodb·nosql
知其然亦知其所以然3 小时前
面试官一开口就问:“你了解MySQL水平分区吗?”我当场差点懵了……
后端·mysql·面试
咖啡Beans3 小时前
MySQL的JSON_函数总结
mysql