一致性非锁定读
指InnoDB引擎通过行多版本的控制的方式读取当前执行时间数据库中的行数据。
之所以称之为非锁定读,是因为他不需要等待访问行上的X锁(排它锁)的释放。他从读取快照中行的数据。一行数据可能不止一个历史数据,可能有多个版本,一般称为行多版本技术,由此带来的并发控制称为多版本并发控制。(MVCC)
在事务隔离级别为READ COMIITED 和RREPEABLE READ(默认隔离级别)下InnoDB使用一致性非锁定读。然而对于快照的定义不同。 READ COMMITED 事物隔离机制下,非一致性锁定读总是读取被锁定数据的行的最新的快照数据。REPEATABLE READ 事物隔离级别事物隔离机制下,非一致性锁定读总是读取被锁定事物开始的行数据的版本。
# 一致性锁定读默认情况下InnoDB 使用一致性非锁定读,而我们如果想要使用一致性锁定读,InnoDB提供了两种类型的加锁语句
- sleect … for update ;对读取数据加X锁,其他事物不能对已锁定的行加任何锁。
- select … lock in share mode;对读取数据加S锁,其他事务不能对已锁定行加X锁。
锁的三种算法
- Record lock 行锁 :单各行加锁
- Gap lock 间隙锁:锁定一个范围,但不锁定记录本身
- Next-Key Lock : Gap Lock + Record Lock :锁定一个范围并锁定记录本身
当查询索引是唯一索引时,InnoDB会对锁进行优化把Next-Key Lock降级为Record Lock,即仅锁住索引本身,而不是范围。而对于辅助索引InnoDB会对辅助索引加Next-key Lock,值得注意的是InnoDB还会对辅助索引的下一个键值范围加Gap Lock。
锁问题
脏读
脏读是指在不同事务下,当前事务可以读取到另外事务未提交的的数据。Mysql InnoDB 事务隔离级别是READ UNCOMMITED 时 就会出现脏读、不可重复读、幻读现象。
不可重复读
不可重复读是指一个事务多次读取同一数据,在这个事务还没有结束时,另外一个事务也访问该数据并对该数据update,然后提交。在第一个事务中前后读到的数据不一致的现象。
不可重复读与脏读的区别:不可重复读是可以读到事务提交以后的数据,脏读是可以读到事务未提交的数据。
Mysql InnoDB 事务隔离级别是REDA COMMITED 时 就会出现不可重复读 、幻读现象。
幻读
一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据不一致。
在可重复读的事务隔离级别下通过对select ... for update 语句显式加写锁来解决幻读现象。
SELECT `id` FROM `users` WHERE `id` = 1 FOR UPDATE;
此语句里For Update 为 id=1 的记录加写锁。默认的写锁算法是 next-key Lock ,如果id是唯一索引就会降级为 record lock,即只锁定id=1的这一行数据,如果id是普通索引就会在该索引加范围行锁(next-key lock),锁定id所在的范围,并未id所在范围的下一范围加范围锁(gap lock)
死锁
死锁是只两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。
死锁解决的方式
- 不要有等待,将任何等待都转化为回滚,并且事务从新开始。但是并发性会降低。
- 超时回滚,为等待事务设置超时时间,若有有个事务超时回滚,另外的事务就至少有一个可以执行。
- 等待图的方法检测死锁,等待图存在回路时,说明存在死锁,回滚undo量小的事务。