观前提醒:作者本人其实也是第一次接触这些内容,所以写的比较基础,会的朋友建议你跳着看。
先来聊聊MySQL的存储引擎,存储引擎属于是MySQL的核心,每一张数据库表都得有自己的存储引擎,官方在MySQL8.4种将它分为了10种,以下为官方介绍,内容为机翻可能不太准确,英语好的可以去看原文:
MySQL服务使用可插入的存储引擎架构,使存储引擎能够加载到正在运行的MySQL服务器中或从其中卸载。
那我们先看InnoDB
引擎,官方的描述中提到:存储引擎是处理不同表类型的SQL操作的MySQL组件。InnoDB
是默认的,也是最通用的存储引擎,Oracle建议将其用于表,但特殊用例除外(在MySQL 8.4
中的CREATE TABLE
语句默认创建InnoDB
表)。
也就是说我们最常用的,同时也是默认的存储引擎是InnoDB
,为什么官方要把它作为MySQL8的默认存储引擎呢?
InnoDB的优点
DML操作遵循ACID模型,事务具有提交、回滚和崩溃恢复功能,以保护用户数据。
行级锁定和Oracle风格的一致读取提高了多用户并发性和性能。
InnoDB
表在磁盘上排列数据,以优化基于主键的查询。每个InnoDB
表都有一个名为聚簇索引的主键索引,它组织数据以最小化主键查找的I/O。为了保持数据完整性,
InnoDB
支持FOREIGN KEY
约束。对于外键,将检查插入、更新和删除操作,以确保它们不会导致相关表之间的不一致。
这是官方的原话,是不是看的一脸懵?那我就来聊下我的理解:
关于第一点:
当我们在执行增删改查这些DML操作的时候,InnoDB
会遵循ACID事务原则,如果一个事务执行失败了InnoDB
会进行回滚rollback
从而避免脏写的问题,保证数据的一致性和安全性。这个很好理解,我有一张余额表balance
和订单表order
,现在用户下单了我要执行创建订单并扣款的操作,如果因为一些原因订单创建成功但扣款失败了,放着不管是不是用户就白嫖了我一单?这是不行的,而如果把这两个操作绑定到同一个事务中,事务中一个动作失败那整个事务就失败了,事务失败会进行回滚,那就不会创建订单,用户也就白嫖失败了,就能保护我们的权益。
关于第二点:
行级锁定或者叫行级锁,这东西是一种用于控制并发访问的一种机制。通过锁定正在被修改的行,它可以防止其他事务在当前事务完成之前读取未提交的数据(避免脏读),或者修改同一行(避免丢失更新)。如果把事务比作人,记录比作房间的话,就大概是:有一天你买了一个妈见打的手办,放在了自己房间里,某天你家里来了很多客人他们想去你房间参观一下(高并发了),然后一堆人走进你的房间看到了你的R18手办,你就社死了(脏读),这不是我们所希望看到的,于是后面你给你的卧室门装了一把锁,现在他们还想进去看时你抢先一步冲进房间然后把房门反锁了并藏好了自己的手办之后再开门,朋友们看不到门后的情况也就不知道你在房间里干嘛,自然就不会想到房间里还有让人社死的手办,你也就不会社死了。行级锁也是一样,加锁后当一个事务在操作一行数据时,别的事务查不到也不能操作被上锁的数据的,只能等当前事务释放锁后下一个事务才能获取锁操作记录,自然也就不会有脏读脏写的问题了。
看名字有行级锁是不是就有表级锁、库级锁这些东西?表级锁确实有,如果把行级锁比作房间的锁的话那表级锁就是房子大门的锁,不过相较于行级锁来说表级锁的并发性能较低,类似于你为了藏你房间的手办,把朋友们都撵到大马路上了,这是不太好的,不让他们进你房间在客厅休息总没事吧。不过表级锁在另一个MyISAM
引擎里面有用到,所以咱后面再讲。
至于这个Oracle风格的一致读取
本质上是一种基于多版本并发控制MVCC
的机制。这种设计借鉴了 Oracle 数据库处理并发读取的核心思想,其核心目的是通过非阻塞的读取操作(无锁读)来提升多用户并发性能。而在InnoDB
中用的方式是快照读,它允许事务看到数据的一个一致视图
,即使其他事务正在对相同的数据进行修改。就像是我在我房间的门上贴了张我进房间之前的照片,我的朋友们即使这会儿进不来我的房间,看看照片是不是也能知道房间里大概有些什么东西?快照读就像是在锁定记录之前用相机给这条记录照了张相,事务在读取数据时,看到的是一个逻辑一致性的快照(Snapshot),这个快照对应事务开始时的数据状态(或在特定隔离级别下的某个时间点)。
InnoDB
中实现这个快照读所用的方式是undo log
,InnoDB
会通过 Undo Log
(回滚日志)保留数据的历史版本。当其他事务修改数据时,当前事务仍然可以读取到修改前的旧版本数据,从而避免直接访问正在被修改的数据页。
哎呀呀,写不动了,明天再写QwQ.
--end--