MySQL ACID、事物隔离、锁、SQL优化
ACID 是数据库事务的一组属性,旨在即使在发生错误、电源故障等情况下也能保证数据有效性。
在数据库环境中,一系列满足 ACID 属性的数据库操作(可以视作对数据的单个逻辑操作)称为事务。
1)Atomicity 原子性:最小工作单元
涉及功能模块(autocommit设置、commit、Rollback语句)
2)Consistency 一致性:即使崩溃异常,数据总是从一个状态到另一个状态
(InnoDB双写缓冲区、InnoDB崩溃恢复区)
3)隔离性(Isolation)防止多个事物并发执行导致事物不一致,分为不同的隔离级别
(事物自动提交autocommit,set transaction Isolation level)
4)持久性(durability)事物一旦提交,所修改的数据就会永久保存到数据库中,
读现象问题:多个事物交叉执行导致的数据不一致情况,
脏读:一个事物能看到其他未提交的修改
不可重复读:一个事物两次查询返回结果不同(解决:加锁读、多版本控制)
幻读:一个事物查询结果返回两个不同得结果集
隔离级别:保证多事物并发数据读写正确
读未提交(READ UNCOMMITTED)
一个事务能够看到其它事务尚未提交的修改,这是最低的隔离水平,允许脏读出现。
这个级别会导致很多问题,从性能上来说,也不会比其它级别好太多,但却缺乏其它级别的很多好处,实际应用中很少使用。
读已提交(READ COMMITTED)
事务能够看到的数据都是其它事务已经提交的修改,也就是保证不会看到任何中间性状态,因此不会出现脏读问题。
但读已提交仍然是比较低的隔离级别,并不保证再次读取时能够获取同样的数据,也就是允许其它事务并发修改数据,允许不可重复读和幻读出现:
同一事务中的一致性读取(Consistent read)总是会设置和读取自己的新快照(snapshot),因此会产生不可重复读问题,因为其它事务可能会并发修改数据。
对于加锁读、UPDATE、DELETE 语句,InnoDB 仅锁定匹配的索引记录。由于禁用了 gap lock,因此会产生幻读问题,因为其它事务可以在间隙(gap)中插入新行。
可重复读(REPEATABLE READ)
这是 MySQL InnoDB 存储引擎默认的隔离级别。
同一事务中的一致性读取(Consistent read)总是会读取第一次读取时建立的快照(snapshot)。
这意味着如果你在同一事务中发起多个普通(非锁定) SELECT 语句,其查询结果是相互一致的。
一致性读取机制保证了同一事务中多次读取的数据是一致的,避免了不可重复读问题,不管其它事务是否提交了 INSERT、DELETE、UPDATE 操作。
如果想每次 SELECT 都返回最新快照,要么隔离级别降为 READ COMMITTED,要么使用加锁读。
对于加锁读、UPDATE、DELETE 语句,加锁行为取决于语句是使用具有唯一搜索条件的唯一索引还是范围类型的搜索条件:
对于具有唯一搜索条件的唯一索引, InnoDB 仅锁定匹配的索引记录。
串行化(SERIALIZABLE)
并发事务之间是串行化的,通常意味着读取需要获取共享读锁,更新需要获取排他写锁,
如果 SQL 使用 WHERE 语句,还会获取 gap lock 和 next-key lock,可能导致大量的超时和锁争用的问题。
这是最高的隔离级别,实际应用中很少使用,只有在非常需要确保数据一致性而且可以接受没有并发的情况下,才会考虑。
附加: MVCC
MVCC 是“多版本并发控制”的缩写。此技术允许具有特定隔离级别的 InnoDB 事务执行一致性读取。
这是一项增强并发性的强大技术,允许并发查询,而无需等待其它事务释放持有的锁。
这项技术在数据库世界中并不普遍。其它一些数据库产品以及 MySQL 存储引擎并不支持。