ACID是什么?在InnoDB中如何实现的?

0 阅读5分钟

引言

大家好啊,我们后端开发中经常会遇到关于数据库设计的问题,那么我们是否真正了解数据库事务处理时的必须具备的四大特性呢?我们今天就以MySQL的默认存储引擎InnoDB来讲讲,它是如何实现ACID的😍

ACID的定义😵

ACID是数据库管理系统(DBMS)为了确保事务处理可靠而必须具备的四个基本属性的缩写。这四个属性分别是:

  1. 原子性(Atomicity) :指整个数据库操作要么全部完成,要么全部不进行。如果在操作过程中发生了错误,那么所有已经执行的操作都会被回滚到操作前的状态,就像这些操作从未发生过一样。
  2. 一致性(Consistency) :确保数据库从一个一致状态转换到另一个一致状态。这意味着事务必须将数据库从一种有效状态带到另一种有效状态,不能违反任何完整性约束条件。
  3. 隔离性(Isolation) :多个事务并发执行时,每个事务之间应该是相互隔离的,即一个事务的执行不应该影响其他事务的执行。不同的隔离级别提供了不同程度的事务间可见性的控制。
  4. 持久性(Durability) :一旦一个事务被提交,它对数据库所做的更改就是永久性的,即使系统出现故障也不会丢失。

上面的官方表述是不是没有理解到位呢?我们往下仔细再看看,你肯定可以理解的👌

InnoDB实现原子性😯

原子性,为什么是原子性呢?

我们学过物理都知道,原子是物质的基本构成单位,尽管原子在物理世界中本身可以再进行拆分,但我们在大部分化学反应和物理反应都将其视为最基本的单位,通俗的来说,也就是不可拆分的一步。我们可以将数据库事务视作为“不可拆分”的一步,里面的操作要么全部完成,要么全部不进行!这就是为什么叫做原子性的原因。

那么InnoDB是如何实现原子性的呢?通过事务日志(redo log和undo log)来实现。当一个事务开始时,所有的修改首先记录在redo log中,并且使用缓冲池(Buffer Pool)来暂存数据页的修改。如果事务失败或中途需要回滚,可以通过undo log恢复到事务开始之前的状态;而当事务成功提交后,即便系统崩溃,重启时也可以根据redo log重做未持久化的修改,从而保证了事务的原子性。

InnoDB实现隔离性😶‍🌫️

为什么是隔离性呢?数据库不是一个整体吗?有这个疑问的小伙伴,要认真看看了。MySQL是支持多个客户端同时连接数据库的,那么这样就带来了并发性问题,如果多个连接对同一份数据读,多个事务直接不是各自一份空间(隔离)那岂不是会乱套了?(比如另一个事务读到了一个事务未提交的数据,但是该事务回滚了,数据更改被取消了,另一个事务读到的就是脏数据)。所以InnoDB实现隔离性,防止出现脏读,不可重复读等问题

InnoDB默认提供的是可重复读(Repeatable Read)级别的隔离性,这是通过多版本并发控制(MVCC, Multi-Version Concurrency Control)技术实现的。MVCC允许查询操作读取事务开始时的数据快照,而不是锁定行,从而减少阻塞并提高并发性能。对于更高要求的隔离级别,如序列化(Serializable),则会采用锁机制来防止幻读等问题。

可重复读,是在事务开始时读取一份快照(Read View),在这个事务进程中,始终使用的是这份快照,这样就可以保证每个事务都是独立的,每个事务内读到的数据都是一致的,是可重复读的。

InnoDB实现持久性🤩

事务一旦提交,就会产生更改,即使系统突然宕机,已经提交的数据也不会丢失,这就是持久性。

一旦事务被提交,其对数据库的改变就会被写入磁盘上的数据文件,以确保即使发生系统故障,已提交的更改也不会丢失。InnoDB利用redo log来快速记录已完成但尚未写入数据文件的事务修改,在系统恢复期间可以依据redo log重新应用这些修改,从而保障了事务的持久性

InnoDB实现一致性😉

举个简单的例子,如果一个银行账户转账事务从账户A转出100元到账户B,在这个事务提交之前,账户A的钱减少了而账户B的钱尚未增加,这将导致数据库暂时处于不一致状态。一致性确保了这种情况不会出现给其他事务看到,并且一旦事务完成,两个账户的余额都会更新为最终正确且合法的状态。在事务开始之前和结束之后,数据库的完整性约束没有被违反,确保数据处于一致的有效状态。这就是一致性。

InnoDB通过支持外键、检查约束等机制来帮助维护数据的一致性。此外,原子性和隔离性的正确实现也是保持数据库一致性的关键因素。一致性也都是依靠其他三个特性才可以实现的。

面试🥲

这是今年暑期某大厂后端面试题之一,要求面试者要理解数据库的四大特性,并通过简短简洁的例子加以说明。相信这篇文章能带给你收获,如果有所收获请点赞加收藏,这是对笔者更新的最大鼓励!!!