MySQL之事务的实现原理

1,158 阅读4分钟

一、事务四大特性

MySQL事务是指在InnoDB引擎下的,MyISAM引擎不支持事务。相信大家都知道事务的四大特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Iosolation)和持久性(Durability)。那么,使用事务是为了达到什么目的呢?

  • 可靠性:数据库在修改数据时可能会抛异常或数据库crash时需要保障数据操作前后的一致性,这时需要知道修改前和修改后的数据,有了undo log和redo log。
  • 并发处理:多个并发请求发送时,其中有对数据就行修改,为了避免读到脏数据,需要对事务之间的读写进行隔离,有了MySQL的隔离级别。

下面主要介绍实现事务的技术,日志文件(undo log和redo log)、锁以及MVCC,以及事务的四大特性是如何实现的。

二、日志文件(undo log和redo log)

1.undo log

undo log—回滚日志,用于记录数据被修改前的信息。为了在发生错误时回滚到数据修改前的状态,将修改前的数据记录下来。

start transaction;
// 生成 回滚日志 balance=1000(原始数据为balance=1000)
update bank set balance = balance - 600 where name="kmli"; 
// 生成 回滚日志 amount=0(原始数据为amount=0)
update finance set amount = amount + 600 where name="kmli";
commit;

每次写入数据或者修改数据之前都会把修改前的信息记录到undo log。

image.png

总结:undo log用来回滚数据的,用于保障未提交事务的原子性。

2.redo log

redo log—重做日志,用于记录数据被修改后的信息。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。redo log防止系统发生宕机或断电时造成已未同步的已修改数据的丢失。

start transaction;
// 生成 重做日志 balance=600(原始数据为balance=1000)
update bank set balance = balance - 400 where name="kmli"; 
// 生成 回滚日志 amount=400(原始数据为amount=0)
update finance set amount = amount + 400 where name="kmli";
commit;

image.png MySQL为了提升性能不会把每次的修改都实时同步到磁盘,而是会先存到Buffer Pool(缓冲池),把这个当作缓存来用。然后使用后台线程去做缓冲池和磁盘之间的同步。

如果还没来得及同步的系统宕机或断电了怎么办?还没来得及执行上面图中红色的操作。这样会导致丢失部分已提交事务的修改信息!
所以引入了redo log来记录已成功提交事务的修改信息,并且会把redo log持久化到磁盘,系统重启之后再读取redo log恢复最新数据。

总结:redo log是用来恢复数据的,用于保障已提交事务的持久化特性。

三、MySQL锁及MVCC

1.MySQL锁

处理并发读或写操作时,通过实现一个由两种类型的锁组成的锁系统来解决问题,分别是共享锁(读锁)和排他锁(写锁)。

  • 共享锁: 又叫读锁,多个读请求可以共享一把锁,不会造成阻塞。
  • 排他锁: 又叫写锁,写锁会排斥其他所有获取锁的请求,一直阻塞,直到写入完成释放锁。

总结:通过读写锁,可以做到读读可以并行,但是不能做到写读,写写并行 事务的隔离性就是根据读写锁来实现的!

2.MVCC(多版本并发控制)

InnoDB的 MVCC ,是通过在每行记录的后面保存两个隐藏的列来实现的。这两个列, 一个保存了行的创建时间,一个保存了行的过期时间,当然存储的并不是实际的时间值,而是系统版本号。

MVCC在MySQL中的实现依赖的是undo log(版本链)与read view(一致性视图)。
READ COMMITTED——每次读取数据前都生成一个ReadView;
REPEATABLE READ——在第一次读取数据时生成一个ReadView。

  • undo log :undo log 中记录某行数据的多个版本的数据。
  • read view :用来判断当前版本数据的可见性

四、事务的实现

前面讲的回滚日志、重做日志以及锁技术就是实现事务的基础。

  • 事务的原子性是通过 undo log 来实现的
  • 事务的持久性性是通过 redo log 来实现的
  • 事务的隔离性是通过 事务隔离级别(读写锁+MVCC)来实现的
  • 一致性是通过原子性、持久性和隔离性来实现的!

ACID只是个概念,事务最终目的是要保障数据的可靠性,一致性。