前言
根据我的计划,接下去文章要涉及到MySQL最关键、最复杂、最牛逼的两个特性:MVCC( Multiversion concurrency control,多版本并发控制)、锁。MySQL为什么要有MVCC和锁?是为了具备事务的能力。那什么是数据库的事务呢?事务是关系型数据库的重要特性,最经典例子是银行转账:A往B转账10元,第一步A账户减10元,第二步B账户加10元。转账的整个过程就是一个事务,事务内的操作要么全部成功,要么全部失败。如果只成功了一部分(A账户扣款成功,B账户加上失败),必须得回滚(A账户的扣款必须回滚)。简单说,数据库的事务就是完整、不可分离的一套写动作。
事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID,缺一不可。MySQL事务的四个特性中ACD三个特性是通过Redo Log(重做日志)和Undo Log (回滚日志)实现的,而隔离性是通过MVCC和锁来实现。所以在介绍MVCC、lock之前,得先了解什么是隔离性,本文将详细介绍MySQL的隔离机制。
另外,目前我们所说的MySQL一般都是默认指InnoDB存储引擎,因为常见的引擎中只有InnoDB支持事务,且只有InnoDB通过索引支持行级锁。
问题
在数据库高并发情况下,不同事物之间的相互读写会产生下列三个问题:
假设有一个表T,只有一列C,该表只有一行数据,值为2.
脏读
脏读就是指当A事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,此时B事务也访问这个数据,然后使用了这个数据。主要针对update
操作。

不可重复读
是指一个事务中多次读同一数据结果不一致。在A事务还没有结束时,B事务也访问该数据。此时在A事务中的两次读数据之间,由于B事务的修改提交,那么A事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。主要针对update
操作。

幻读
幻读并不是说两次读取获取的结果集不同,幻读是某一次的查询操作得到的结果无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。主要针对insert
操作。
注意:不可重复读的和幻读很容易混淆。不可重复读侧重表达读-读,即两次读的数据不一致。而幻读则是说读-写,强调的是读到之前没有出现过的数据,用写来证实读的是鬼影。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

定义
隔离性是指事务内部的操作与其他事务是隔离的,并发执行的各个事务之间读写不能互相干扰。简单起见,我们仅考虑最简单的读操作和写操作(暂时不考虑带锁读等特殊操作),那么隔离性的探讨,主要可以分为两个方面:
(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性。
(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性。
为了解决脏读、不可重复读和幻读问题,MySQL通过事务隔离机制实现。有以下四种隔离机制:
READ-UNCOMMITTED(读未提交)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。读取未提交的数据,也被称之为脏读。
READ-COMMITTED(读已提交)
事务提交后,做得变更才能被其他事务看到。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。解决了脏读。
REPEATABLE-READ(可重复读)
一个事务执行过程中看到的数据,总是跟跟这个事务启动的时候看到的数据时是一致的。未提交变更,在其他事务是不可见的。解决了不可重复读。
注意:RR是官方MySQl的默认隔离级别,阿里云RDS的隔离级别默认是RC。
SERIALIZABLE(串行化)
对于同一行记录,写和读都会加锁,当出现读写锁冲突的时候,后访问的。解决了幻读。
以上四种是MySQL的隔离制度,四种隔离级别是逐级严格,事务级别越严格,并发性越差,隔离性越好。我们往往需要在隔离性和并发性做一个平衡。
另外,事务隔离级别支持会话级、全局级动态修改(重启后失效),也可以在配置文件中加入(需要重启生效),但是修改时要注意大写,否则会失败。
会话动态修改示例(右划观看效果更佳):
mysql>set transaction_isolation='REPEATABLE-READ';Query OK, 0 rows affected (0.00 sec)mysql>mysql>show variables like '%transaction_isolation%';+-----------------------+-----------------+| Variable_name | Value |+-----------------------+-----------------+| transaction_isolation | REPEATABLE-READ |+-----------------------+-----------------+1 row in set (0.00 sec)

附录
MySQL各个引擎属性(右划观看效果更佳)
mysql>select * from information_schema.`ENGINES`\G;*************************** 1. row ***************************ENGINE: CSVSUPPORT: YESCOMMENT: CSV storage engineTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 2. row ***************************ENGINE: MRG_MYISAMSUPPORT: YESCOMMENT: Collection of identical MyISAM tablesTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 3. row ***************************ENGINE: MyISAMSUPPORT: YESCOMMENT: MyISAM storage engineTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 4. row ***************************ENGINE: BLACKHOLESUPPORT: YESCOMMENT: dev/null storage engine (anything you write to it disappears)TRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 5. row ***************************ENGINE: PERFORMANCE_SCHEMASUPPORT: YESCOMMENT: Performance SchemaTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 6. row ***************************ENGINE: MEMORYSUPPORT: YESCOMMENT: Hash based, stored in memory, useful for temporary tablesTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 7. row ***************************ENGINE: ARCHIVESUPPORT: YESCOMMENT: Archive storage engineTRANSACTIONS: NOXA: NOSAVEPOINTS: NO*************************** 8. row ***************************ENGINE: InnoDBSUPPORT: DEFAULTCOMMENT: Supports transactions, row-level locking, and foreign keysTRANSACTIONS: YESXA: YESSAVEPOINTS: YES*************************** 9. row ***************************ENGINE: FEDERATEDSUPPORT: NOCOMMENT: Federated MySQL storage engineTRANSACTIONS: NULLXA: NULLSAVEPOINTS: NULL9 rows in set (0.00 sec)ERROR:No query specified




