MySQL锁,事务,MVCC是什么

  介绍

这篇文章将为大家详细讲解有关MySQL锁,事务,MVCC是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。


<节>

以下内容摘自《高性能MySQL》(第3版)

<引用类=" multiquote-1 ">

MySQL默认采用自动提交(AUTOCOMMIT)模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMIT变量来启用或者禁用自动提交模式

事务具有酸四大特性,那么MySQL是如何实现事务的这四个属性的呢?

    <李> <节>

    原子性   要么全部成功,要么全部失败.MySQL是通过记录undo_log的方式来实现的原子性.undo_log即<强>回滚日志强,在真正的SQL执行之前先将undo_log写入磁盘,然后再对数据库的数据进行操作。如果发生异常或回滚,就可以依据undo_log进行反向操作,恢复数据在事务执行之前的样子。

    <李> <节>

    持久性   事务一旦被正常提交,它对数据库的影响就应该是永久的。此时即使系统崩溃,修改的数据也不会丢失。InnoDB 作为 MySQ L的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB 提供了缓存(Buffer Pool),作为访问数据库的缓冲:当从数据库读取数据时,会首先从 Buffer Pool 中读取,如果 Buffer Pool 中没有,则从磁盘读取后放入 Buffer Pool ;当向数据库写入数据时,会首先写入 Buffer Pool,Buffer Pool 中修改的数据会定期刷新到磁盘中。

    这样的设计也带来了相应的问题:如果数据提交了,这时数据还在缓冲池里(还没刷盘),此时MySQL宕机、断电了怎么办?数据会不会丢失?

    答案是不会,MySQL 通过 redo_log 的机制,保证了持久性。redo_log 即重做日志,简单说就是当数据修改时,除了修改 Buffer Pool 中的数据,还会在 redo_log 记录这次操作;当事务提交时,会调用 fsync 接口对 redo_log 进行刷盘。如果MySQL宕机,重启时可以读取 redo_log 中的数据,对数据库进行恢复。

  • 隔离性

    隔离性是 ACID 里面最复杂的一个,这里面涉及到隔离级别的概念,一共有四个

    • Read uncommitted
    • Read committed
    • Repeatable read
    • Serializable

    简单说隔离级别就是规定了:一个事务中数据的修改,哪些事务之间可见,哪些不可见。而隔离性就是要管理多个并发读写请求的访问顺序。

    MySQL 对于隔离性的具体实现我们后面会展开说。

  • 一致性

    通过回滚、恢复和在并发环境下的隔离做到一致性。

通过上个问题我知道单条 DDL 执行也会被当成一个事务自动提交,那么无论是多条SQL并发,还是多个自己手动组织的包含多条SQL的事务并发,都会导致事务并发问题。

具体来说有:

  • 脏写 (一个事务提交的数据覆盖了另一个事务未提交的数据)
  • 脏读 (一个事务读取到另一个事务未提交的数据)
  • 不可重复读 (重点在于update和delete 一个事务内多次读取的数据不一样)
  • 幻读 (重点在于insert 一个事务内多次读取的记录数不一样)

上面我们提到了事务的隔离级别,MySQL 的所有隔离级别都能保证不产生脏写,所以就剩下脏读、不可重复读和幻读的问题了。

下面具体看下各隔离级别是如何解决或未解决上面这些问题的:

未提交读,这个级别在读的过程中不会加任何锁,只在写请求时加锁,所以写操作在读的过程中修改数据,就会造成脏读。也自然会产生不可重复读和幻读。

已提交读,与未提交读一样也是读不加锁,写加锁。不一样的是利用了 MVCC 机制避免了脏读的问题,同样会有不可重复读和幻读的问题。关于 MVCC 我们后面会详细说。

MySQL 默认的隔离级别,在这个级别 MySQL利用两种方式解决问题

  1. 读写锁   读读并行时加读锁,读读是共享锁的。   只要有写请求就加写锁,这样读写是串行的。   读取数据时加锁,其它事务无法修改这些数据,所以不会产生不可重复读。   修改删除数据时也要加锁,其它事务无法读取这些数据,所以不会产生脏读。   第一种方式就是我们常说的

    MySQL锁,事务,MVCC是什么