Mysql(三)--事务 & 隔离级别 & MVCC

什么是数据库事务?

数据库事务就是一组数据库操作,要么全部成功要么全部失败。

特性

事务有四个特性(ACID),并且四个特性都必须要满足:(特性其实也就是特点)

原子性(Atomicity):一组操作,要么全部成功、要么全部失败。

一致性(Consistency):事务执行前与执行后数据完整性是一致的,没有收到破坏。

隔离性(Isolation):多个事务操作之间是隔离的,互不干扰。

持久性(Durability):数据变更是永久的。

事务并发带来的问题

如果事务处理是单线程的,那不会有问题,但是多个事务并发执行,就会产生一些问题:

  • 脏读:(当前事务)读取了(其他事务)未提交的数据
  • 不可重复读:(当前事务)读取了(其他事务)已经提交的数据
  • 幻读:(当前事务)读取了(其他事务)新增的数据

为此,InnoDB的四个隔离级别就是为了解决上述的问题:

四个隔离级别为:读未提交、读已提交、可重复读、串行化,映射图如下(这样就很清楚了)

Mysql默认的事务隔离级别就是:可重复读

事务的实现原理(就是使用什么方式去实现事务的这个四大特性的)

以下都是以InnoDB引擎为例:

持久化:Redo log(重做日志)

redolog会记录已经提交的事务信息,也就是修改后的数据的信息

Mysql为了提高性能不会每次修改操作都去直接写入磁盘,会先写入内存缓冲区中,后续等系统空闲时候刷盘到磁盘中就行。

但是此时会出现一个问题:如果内存缓冲区中的数据还没落盘,发生了宕机,数据就丢失了,因此引入了Redolog,在提交事务后,会立即持久化写一份Redolog记录,来帮助数据恢复。

原子性:Undo log(回滚日志)

Undo log 是用来记录事务提交之前的数据,也就是记录了修改之前的数据。

当系统发生问题,或者接收到 rollback 命令进行回滚的时候,就使用 Undolog 来帮助恢复数据。

 

Mysql 锁

有读锁和写锁之分

记录锁、间隙锁、临键锁,共享锁、排他锁,意向锁

 

 

MVCC(多版本控制)

MVCC 的核心点在于如何从 UndoLog(回滚日志中)读取正确的历史版本信息

逻辑如下图:

 

mvcc 只能解决部分幻读:开始查询不到,但是可以修改新记录,然后再查询就查到了(参考:https://xie.infoq.cn/article/7eafabc80c1ab0a8ccc7f1151)

真正解决幻读需要加锁才可以。通过间隙锁可以解决,如下所示:

快照读 和 当前读

快照读【Consistent Read】

也叫普通读,读取的是记录数据的可见版本,不加锁,不加锁的普通select语句都是快照读,即不加锁的非阻塞读。

快照读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁。

 

当前读

也称锁定读【Locking Read】,读取的是记录数据的最新版本,并且需要先获取对应记录的锁。如下语句:

SELECT * FROM student LOCK IN SHARE MODE;  # 共享锁
SELECT * FROM student FOR UPDATE; # 排他锁


-- 如果只使用一下语句,而不适用上面的2个语句进行加锁,则会产生幻读问题
INSERT INTO student values ...  # 排他锁
DELETE FROM student WHERE ...  # 排他锁
UPDATE student SET ...  # 排他锁

 

如何解决幻读?

在 InnoDB RR(可重复读) 模式下:

快照读:使用MVCC可以解决幻读

当前读:使用记录锁(根据主键或者唯一索引可以定位到具体行时候即为记录锁) or 间隙锁 (无法定位到具体行时候即为间隙锁)就可以解决可以解决幻读。

 

 

 

 

参考:

事务:https://segmentfault.com/a/1190000044496665#item-8-6

posted @ 2024-12-20 17:21  lenbkan  阅读(14)  评论(0编辑  收藏  举报