美文网首页
MySQL 事务知识整理

MySQL 事务知识整理

作者: 章光辉_数据 | 来源:发表于2020-12-14 21:12 被阅读0次

    最近在招 DBA ,在面试的过程中,通过学习也加深了对事务这一概念的理解,下面做个简单的整理。

    1、什么是事务

    事务是由一步或几步数据库操作序列组成逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行。

    事务是在引擎层实现的,在 MySQL 中只有使用了 Innodb 引擎的数据库或表才支持事务。MyISAM 引擎就不支持事务。

    2、事务的作用

    事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。

    事务用来管理 insert, update, delete 语句。

    3、事务的 ACID 特性

    原子性 Atomicity
    又叫不可分割性,要么全完成,要么全不完成。就像原子是物质的最小组成单位一样,原子内的各种操作是一个整体。如果执行过程中发生了错误,就会回滚到最初状态。

    一致性 Consistency
    事务开始前和事务结束后,数据库的完整性不会被破坏,这表明操作的数据必须符合所有规范。

    隔离性 Isolation
    又叫独立性,数据库允许多个事务同时执行,隔离性可以防止多个事务并发执行导致数据的不一致。

    持久性 Durability
    事务处理结束后,对数据的修改是永久的,即使系统故障也不会丢失。

    4、事务的隔离级别

    下面的 4 种隔离级别,越往下,效率越低,并发越低,安全性越高。


    1)读未提交(Read Uncommitte,RU)

    • 定义:所有事务都可以看到其他未提交事务的执行结果。
    • 说人话:一个事务里可以读到别人还没有提交的变更。别人可能处理成功,也可以回滚,导致你读到的数据不一定是对的。
    • 优点:效率最高,并发最强
    • 缺点:可能导致脏读、幻读、非重复读,安全性最低

    2)读提交(Read Committed,RC,Oracle 默认的隔离级别)

    • 定义:事务在提交之前,做的变更都无法被其它事务看见,但是事务本身可以看到数据库的变更。
    • 说人话:一个事务里可以读到别人已经提交的变更,即读取最新一份快照数据。如果一个事务里有两次读,两次读的期间别人完成了操作,就会导致两次读的虽然都是真的(不是脏读),但是结果不一样(非重复读)。
    • 优点:效率稍高,并发稍强
    • 缺点:可能导致幻读、非重复读,安全性较低

    3)可重复读(Repeatable Read,RR,MySQL 默认的隔离级别)

    • 定义:事务总是只能看到在启动的那个时刻,数据库的状态,即在事务未提交之前,自己做的变更别的事务看不见,数据库中的变更自己也看不见。
    • 说人话:一个事务里,不会读取别的事务提交的变更,而是会读取事务开始时的快照数据
    • 优点:不会导致脏读、非重复读
    • 缺点:当快照读和当前读混用时,会导致幻读

    MySQL Innodb 引擎是如何避免幻读的
    MySQL Innodb 引擎做了特殊实现,即加锁。在 RR 级别下,如果查询条件使用了唯一索引,就会对读取到的记录加上行锁;如果查询条件是一个范围查询,那么就会对读取到的记录加上 gap 锁(间隙锁)或者 next-key 锁 ( 行锁 + 间隙锁),避免幻读。
    一个事务里,不会读取别的事务提交的变更,而是会读取事务开始时的快照数据。

    很多人无法区分幻读与不可重复读,这里简单做个对比。

    幻读与不可重复读的区别
    不可重复读:在一个事务中多次读取同一个数据时,结果出现不一致。


    幻读:在一个事务中使用相同的 SQL 两次读取,第二次读取到了其他事务新插入的行。

    4)串行化(Serializable)

    • 定义:事务对某一行的操作会加锁,“写”会加“写锁”,“读”会加“读锁”,在锁释放掉之前,其它的事务都无法都这一行的记录进行操作。必须等之前的事务执行完毕,释放锁。后面的事务又会重新加锁。
    • 说人话:事务执行的时候,会将使用的数据范围锁起来不让别人用,所有事务排队执行。
    • 优点:安全性最高
    • 缺点:效率最低、并发最低

    总结一下:

    隔离级别 是否允许脏读 是否允许非重复读 是否允许幻读
    读未提交(RU)
    读提交(RC) X
    可重复读(RR) X X √(MySQL InnoDB 是 X)
    串行化 X X X

    隔离的越严实,效率就越低,并发越低,安全性越高。

    5、事务的实现原理

    事务的隔离性是通过锁实现的,事务的一致性和持久性是通过 Redo Log (重做日志)实现的,事务的原子性是通过 Undo Log (回滚日志)实现的。

    5.1、隔离性的实现

    事务的实现是基于数据库的存储引擎。不同的存储引擎对事务的支持程度不一样。MySQL 中支持事务的存储引擎有 InnoDB 和 NDB。

    InnoDB 是 MySQL 默认的存储引擎,默认的隔离级别是 RR(可重复读),并且在 RR 的隔离级别下更进一步:

    1. 用多版本并发控制(MVCC )解决不可重复读问题:MVCC 允许一个行记录可能有不止一个快照数据,因此使用快照读就可以实现可重复读。
    2. 用行锁 + 间隙锁解决幻读问题:行锁避免了数据的 update/delete,间隙锁避免了数据的 insert 。

    因此 InnoDB 的 RR 隔离级别其实也实现了串行化级别的效果,而且保留了比较好的并发性能。

    5.2、一致性和持久性的实现

    在 InnoDB 的存储引擎中,事务通过 Redo Log 和 InnoDB 存储引擎的日志缓冲( InnoDB Log Buffer ) 实现一致性和持久性。

    • 事务开启时:事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是 DBA 们口中常说的“日志先行”(Write-Ahead Logging)。
    • 事务提交之后:在 Buffer Pool 中映射的数据文件才会慢慢刷新到磁盘。此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据 Redo Log 中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。

    5.3、原子性的实现

    在事务执行的过程中,除了记录 Redo Log,还会记录 Undo Log 。

    Undo Log 主要为事务的回滚服务。Undo Log 记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据 Undo Log 进行回滚操作。

    单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。

    6、MySQL 事务控制

    MySQL 里的事务控制语句有:

    • 开启事务:beginstart transaction
      tables 被执行。
    • 提交事务:commitcommit work ,使对数据库进行的所有修改成为永久性的。
    • 回滚事务:rollbackrollback work,会结束用户的事务,并撤销正在进行的所有未提交的修改。注意,所有的 DDL 语句是不能回滚的,并且部分的 DDL 语句会造成隐式的提交。
    • 创建保存点:savepoint identifier,一个事务中可以有多个 savepoint;
    • 删除保存点:release savepoint identifier,当没有指定的保存点时,执行该语句会抛出一个异常
    • 回滚事务到保存点:rollback to identifier
    • 设置事务的隔离级别:set transaction
    • 修改自动提交模式:set autocommit=0 代表禁止自动提交,=1代表开启自动提交。

    相关文章

      网友评论

          本文标题:MySQL 事务知识整理

          本文链接:https://www.haomeiwen.com/subject/pvdhbktx.html