tangjianft 2020-02-15
1、一致性的非锁定读
一致性的非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versionning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放,相反地,InnoDB存储引擎会去读取行地一个快照数据。
快照数据是指该行地之前版本地数据,该实现是通过undo段来完成。而undo用来在事务中回滚数据,因此快照数据本身是没有额外地开销。此外,读取快照数据是不需要上锁地,因为没有事务需要对历史数据进行修改操作。
非锁定读机制极大地提高了数据库的并发性。在InnoDB存储引擎地默认设置下,这是默认地读取方式。即读取不会占用和等待表上的锁。但是在不同事务隔离级别下,读取的方式不同,并不是在每个事务隔离级别下都是采用非锁定的一致性读,此外,即使都是使用非锁定的一致性读,但是对于快照数据的定义也各不相同。
快照数据其实就是当前行数据之前的历史版本,每行记录可能有多个版本。一般称这种技术为行多版本技术。因此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control,MVCC).
在事务隔离级别 READ COMMITTED 和 REPEATABLE READ 下,InnoDB存储引擎使用非锁定的一致性读。然而,对于快照数据的定义却不相同。
在READ COMMITTED 事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。
而在REPEATABLE READ 事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。
对于READ COMMITTED 的事务隔离级别而言,从数据库理论的角度来看,其违反了事务ACID的I的特性,即隔离性。
2、一致性锁定读
默认情况下InnoDB存储引擎的select操作使用一致性非锁定读。但是在某些情况下,用户需要显式地对数据库读取操作进行加锁以保证数据逻辑地一致性。而这要求数据库支持加锁语句,即使是对于select的只读操作。
InnoDB存储引擎对于select 语句支持量两种一致性的锁定读(locking read)操作:
SELECT ..... FOR UPDATE 排他锁X
SELECT ..... LOCK IN SHARE MODE 共享锁S
SELECT ..... FOR UPDATE 对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。SELECT ..... LOCK IN SHARE MODE 对读取的行记录加一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,则会被阻塞。
对于一致性非锁定读,即使读取的行已被执行了SELECT ..... FOR UPDATE ,也是可以进行读取的。
begin ,start transaction ,set autocommit=0 手动开始事务
commit;提交事务
rollback;回滚事务
3、自增长与锁
在InnoDB存储引擎的内存结构中,对于每个含有自增长值得表都有一个自增长计数器(auto-increment counter)。当对含有自增长得计数器得表进行插入操作时,这个计数器会被初始化,执行如下语句来得到计数器得值:
SELECT MAX(auto_inc_conl) FROM t FOR UPDATE;
插入操作会依据这个自增长得计数器值加1 赋予自增长列。这个实现方式称做AUTO-INC Locking。这种锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长插入的SQL语句后立即释放。
虽然AUTO-INC Locking从一定程度上提高了并发插入的效率,但是还存在一些性能上的问题。首先,对于有自增长值得列得并发插入性能较差,事务必须等待前要给插入的完成(虽然不用等待事务的完成),其次,对于 INSERT ... SELECT 的大数据量的插入会影响插入的性能,因为另一个事务中的插入会被阻塞。
从MySQL 5.1.22 版本开始,InnoDB存储引擎中提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了自增长值插入的性能。使用innodb_autoinc_lock_mode来控制自增长的模式。
另外,在InnoDB存储引擎中,自增长值得列必须是索引,,同时必须是索引得第一个列。
4、外键和锁
外键主要用于引用完整性得约束检查。在InnoDB存储引擎中,对于一个外键列,如果没有显式地对这个列加索引,InnoDB存储引擎自动对其加一个索引,因为这样可以避免表锁。
对于外键值的插入或更新,首先需要查询父表中的记录,即SELECT 父表.但是对于父表的SELECT 操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致的问题。因此这时使用的是 SELECT .... LOCK IN SHARE MODE 方式,即主动对父表加一个S锁,如果这时父表上已经这样加X锁,子表上的操作会被阻塞。