InnoDB-- 锁
1. 什么是锁
锁是数据库系统区别于文件系统的一个关键特性。锁机制用于管理对共享资源的并发访问。InnoDB存储引擎会在行级别上对表数据上锁。InnoDB存储引擎也会在数据库内部共他多个地方使用锁,从而允对许多种不同资源提供并发访问。
2. lock与latch
latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差。在InnoDB存储引擎中,latch又可以分为mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
lock的对象是事务,用来锁定的是数据库的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放。
latch可以使用showengine innodb mutex进行查看
输出结果参数说明
3. InnoDB存储引擎中的锁
a. 锁的类型
i. 共享锁(S Lock),允许事务读一行数据。
ii. 排他锁(X Lock),允许事务删除或更新一行数据。
如果一个事务T1已经获得了行R的共享锁,那么另外的事务T2可以立即获得行R的共享锁,这种情况称为锁兼容(Lock Compatible)。但若有其他的事务T3想获得行R的排他锁,则其必须等待事务T1,T2释放行R上的共享锁(锁不兼容)。
X锁与任何的锁都不兼容,而S锁仅和S锁兼容。先要特别注意的是,S和X都是行锁,兼容是指对同一记录(ROW)锁的兼容性情况。
InnoDB存储引擎支持多粒度(granular)锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁(Intention Lock)。
如果需要对页上的记录R进行上X锁,那么分别需要对数据库A、表、页上意向锁IX,最后对记录R上X锁。其中任何一部分导致等待,那么该操作需要等待粗粒度锁的完成。举例来说,在对记录R加X锁之前,已经有事务对表1进行了S锁,那么表1上已经存在S锁,之后事务需要对记录R在表1上加上IX锁,由于不兼容,所以该事务需要等待表锁操作的完成。
意向锁类型:
1. 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁。
2. 意向排他它(IX Lock),事务想要获得一张表中某几行的排他锁。
在Information_schema架构下使用
Innodb_trx、Innodb_locks、innodb_lock_waits监控当前事务并分析可能存在的问题。
Innodb_trx说明:
Innodb_locks说明:
Innodb_lock_waits说明:
b. 一致性非锁定读
一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行delete或update操作,这时读取操作不会因此去等待行上锁的释放。相反地,InnoDB存储引擎会读取行的一个快照数据。一个行记录可能不止一个快照数据,一般称这种技术为多版本技术(MVCC)。
在事务隔离级别read commited和repeatable read(InnoDB默认隔离级别)下,InnoDB存储引擎使用非锁定的一致性读。然而对快照数据的定义却不相同。在read commited事务隔离下,对快照数据,非一致读总是读取被锁定行的最新一份快照数据。而在repeatable read 事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。
c. 一致性锁定读
在某些情况下,用户需要显式地对数据库读取操作进行加锁以保证数据逻辑的一致性。这要求数据库支持加锁语句。
1. Select…… for update
读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。
2. Select…… lock in share mode
对读取的行记录加一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,则会被阻塞。
d. 自增长与锁
执行如下语句得到计数器:
Select max(auto_inc_col) from t for update;
插入操作依据这个自增长的计数器值加1赋予自增长列。这个实现方式称做auto_inclocking。为了提高插入性能,锁不是在一个事务完成后才释放,而是在完成对自长值插入的SQL语句后立即释放。
Auto_inc locking 在一定程序上提高了并发插入效率,但还存在一些性能上的问题。1.并发插入性能效差。2.对于insert … select的大数据量的插入会影响。
从mysql 5.1.22版本开始,InnoDB存储引擎中提供了一种轻量互斥量的自增长实现机制,这种机制大提高了自增长插入的性能。InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长的模式,默认值为1。
插入类型:
Innodb_autoinc_lock_mode说明
InnoDB存储引擎中自增长的实现和MyISAM不同,MyISAM存储引擎是表锁设计,自增长不考滤并发插入的问题。
e. 外键和锁
对于外键值的插入或晚新,首先需要查询父表中的记录。但是对于父表的SELECT操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致,因此这时使用的是SELECT … LOCK IN SHARE MODE方式。
4. 锁的算法
a. 行锁的3种算法
i.Record Lock:单个记录上的锁
总是会去锁住索引记录,如果InnoDB存储引擎在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁表。
ii.Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
iii.Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身,当查询的索引含有唯一属性时,会进行优化,降级为Record Lock。
5. 锁问题
a. 脏读
脏读是指事务对缓冲池中行记录的修改,并且还没有被提交。脏数据是指未提交的数据。一个事务读取到别一个事务未提交的数据,则违反了数据的隔离性。
b. 不可重复读
不可重复读是指一个事务内多次读取同一数据集合。
不可重复读与脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的却是已提交的数据,但是其违反了数据库事务一致性的要求。
c. 丢失更新
一个事务的更新操作会被另一个事务的更新所覆盖。
6. 阻塞
一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源,这就是阻塞。
InnoDB引擎中,使用innodb_lock_wait_timeout用来控制等待的时间(默认是50秒),innodb_rollbak_on_timeout用来设定是否在等待超时时对进行中的一事务进行回滚操作(默认是OFF,不回滚)
7. 死锁
a. 概念
死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
解决死锁最简单的一种方法是超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚。使用innodb_lock_wait_timeout用来设置超时的时间。
Wait-for graph(等待图)进行死锁检测
b. 死锁的概率
8. 锁升级
当前锁的粒度降级。
发生锁升级的情况:
a. 由一句单独的SQL语句在一个对象上持有的锁的数量超过了阈值,默认为5000.
b. 锁资源占用的内存超过已**内存的40%