《MySQL实战45讲笔记》03、事务隔离:为什么你改了我还看不见?

大家好,我是被白菜拱的猪。

一个热爱学习废寝忘食头悬梁锥刺股,痴迷于girl的潇洒从容淡然coding handsome boy。

在这里插入图片描述

本篇是《MySQL实战45讲》第三讲笔记,之前采取通过自己的语言对内容进行复述,效果很好,但是时间耗费太大,两个小时也没写完一讲,尤其在当下时间之急迫,采用如此方式是较为不妥的,所以接下来采取以问答的方式对内容进行抽取总结,方便日后复习。

强烈推荐《MySQL实战45讲》,此专栏杠杠的。

通过本讲了解到什么是事务、事务的特性、以及并发事务会导致什么问题,从而产生了隔离级别的概念,以及隔离级别的实现方式、其中又涉及到 MVVC、undo log(回滚日志)。

事务的启动方式、为什么不建议使用长事务等等。

事务是针对存储引擎而言,MySQL 原生的存储引擎 MyISAM 没有事务,本文讲的是带有事务的 InnoDB。

  1. 事务的概念:要么全部成功,要么全部失败

  2. 事务的特性:ACID(Atomicity、Consistency、Isolation、Durability)原子性、一致性、隔离性、持久性

    • 原子性:事务是最小的执行单位,不可分割。
    • 一致性:事务在执行前后,数据保持一致,如转账时,双方的总和是不变的。
    • 隔离性:并发操作数据库时,一个事务不能被其他事务干扰,各个事务保持独立。
    • 持久性:一个事务被提交之后,它对数据库中数据的改变是持久的。
  3. 并发事务带来哪些问题?脏读、不可重复读、幻读。

    • 脏读:一个事务读取到另一个未提交事务的数据。假如未提交事务进行回滚,那么之前读取的数据就是错误的,就是脏数据。
    • 不可重复读:一个事务读取到另一个事务已经提交的更改数据。一个事务内多次读取同一数据,在这个事务还没有结束时,另一个事务也访问该数据,并做了修改提交,就会导致第一个事务两次读到的数据不一致。
    • 幻读:一个事务读取到另一个事务已经提交的新增数据。一般在统计数据的事务中发生错误。
    • 容易混淆的是不可重复读和幻读,主要的区别的前者读取的是更改的数据,后者读取的是新增的数据。采取的对策也不同,不可重复读针对的是行,可以添加行级锁,幻读针对的是表,加表级锁。
  4. 解决上述问题,引出了隔离级别的概念。当然,隔离越严实,效率越低。SQL 标准的隔离级别有 读未提交(read uncommitted)、读提交(read commited)、可重复读(repeatable read)、串行化(serializable)。

    • 读未提交:一个事务还没有提交时,它所做的变更就能被其他事务看到。
    • 读提交:一个事务提交之后,它所做的变更才能被其他事务看到。
    • 可重复读:一个事务在执行过程中所看到的数据,跟它在刚开始启动时所看到的数据是一致的。
    • 串行化:顾名思义是对同一行记录,写会加锁,读也会加锁,当读写锁发生冲突时,后一个事务必须等前一个事务执行完成后才能执行。
  5. 隔离级别的实现:

    数据库会创建一个视图,访问的时候以视图的逻辑结果为基准。“可重复读” 是在事务启动时创建视图,所以在事务中,从始至终都是该视图。“读提交”是在每个 SQL 语句开始执行的时候创建的,所以能够读到别的事务提交过的数据。“读未提交”没有创建视图,直接返回记录上的最新值。同样串行化也没有视图概念,它是采用加锁的方式来避免并发访问。

具体的讲:

在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。不同时刻启动的事务会有不同的 read-view,这也造成同一个记录在系统中有多个版本,这就是数据库的多版本并发控制(MVVC),这些记录都记录在undo log (回滚日志)中。

为什么能通过rollback能回到提交前的状态也就是这个原因。

  1. 回滚日志什么时候删除?

    在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。

    什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的 read-view 的时候。

  2. 为什么不使用长事务?

    长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

  3. 事务的启动方式

    1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
    2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

    假如觉得每次主动执行 commit 后在 begin 过于麻烦,则可以使用 commit work and chain,则是提交事务并自动启动下一个事务。

学习路长漫漫,我与你同行。

猜你喜欢

转载自blog.csdn.net/weixin_44226263/article/details/113881500
今日推荐