文章目录
锁的出现主要是最大程度利用数据库的并发访问的同时,还要确保每个用户能以一致的方式读取和修改数据
1. 什么是锁
锁机制用于管理对共享资源的并发访问.InnoDB存储引擎会在行级别上对表数据上锁.数据库系统使用锁是为了支持对共享资源并发访问,提供数据的完整性和一致性.
MyISAM存储引擎使用表锁,读取性能良好,但是并发插入性能就要差一些.
2. lock与latch
锁分为两种:lock与latch.在数据库中,lock与latch都可以被称为锁,但是latch一本被称为闩(shuan)锁(轻量级).要求锁定的时间非常短,如果持续时间成,应用的性能会非常差.
在InnoDB存储引擎中,latch又可以被分为mutex(互斥量)和rwlock(读写锁).设计的目的是用来摆正并发线程操作临界资源的正确性,通常没有死锁检测.
lock的对象是事务,用来锁定的是数据库中的对象(表,页,行等).一般lock的对象只在事务提交或者回滚后释放,有死锁机制.
lock与latch的比较:
lock | latch | |
---|---|---|
对象 | 事务 | 线程 |
保护 | 数据库内容 | 内存数据结构 |
持续时间 | 整个事务过程 | 临界资源 |
模式 | 行锁,表锁,意向锁 | 读写锁,互斥量 |
死锁 | 有死锁检测和处理 | 仅通过应用程序的顺序保证无死锁现象 |
存在于 | lock manager的哈希表 | 每个数据结构的对象中 |
3. InnoDB存储引擎中的锁
(1). 锁的类型
InnoDB存储引擎实现了以下两种锁:
- 共享锁(S Lock,读锁),允许读取一行数据
- 排他锁(X Lock,写锁),允许事务删除或者更新一行数据
以上两种都是行锁
读锁和读锁之间是兼容的,写锁与任何锁都不兼容.
I nnoDB存储引擎支持意向锁,即表级别的锁:
意向锁是为了解决行锁和表锁共存时产生冲突的问题而产生的.
当一个事务A得到了表中一行的行锁时,另一个事务B获取到整个表的表锁,那么两个锁就会冲突.
那么,在给一行加行锁时,先给整个表加上意向锁,那么在加表锁时会先判断意向锁(因为意向锁是表锁),然后再进行加锁.
这里的锁都指的是写锁.
- 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁
- 意向排它锁(IX Lock),事务想要获得一张表中某几行和排它锁
可以通过三张表来简单的监控当前事务并分析可能存在的锁问题:
- INNODB_TRX:显示InnoDB当前运行的事务
- INNODB_LOCKS:显示每张表的锁情况
- INNODB_LOCK_WAITS:显示当前事务的等待
表的详情信息参考MySQL技术内幕InnoDB存储引擎第二版P255-257
(2). 一致性非锁定读
不加锁读,也就是读之前某一时刻的快照
一致性的非锁定读是指InnoDB存储引擎通过行多版本空值的方式开读取当前执行时间数据库中行的数据.(多版本读取快照)
快照数据是指该行的之前版本的数据,是通过undo段(用于回滚的老版本数据链中的一个节点)来完成的,因此没有任何空间开销.
一致性非锁定读是InnoDB存储引擎默认的读取方式,但是不同的事务隔离情况下,读取的方式可能会发生改变(或者快照数据的定义不同).
读未提交和可重复读下,使用一致性非锁定读,但是读未提交中总是读取最新的一份快照数据,而可重复读下,读取事务开始是的行数据版本.
在默认情况下,可以读到的其他事物提交前的数据,这里是指undo页中的回滚数据,而不是说数据库中的数据未发生改变.
(3). 一致性锁定读
当前读,也就是加读锁
- select…for update : 加写锁
- select…lock in share mode : 加读锁
(4). 自增长与锁
每一个自增长的插入:
开启事务 --> 获取自增长值 --> 重新设置自增长值 --> 插入相应数据 --> 提交事务
|________________________________|
|
锁有效
自增长是通过自增长计数器实现的,每当对含有自增长计数器的表进行插入操作时,计数器就会被初始化,并通过查询当前表自增长列的最大值来重新设置值.这个查询的过程中,需要对表进行加锁.而这个锁在select语句执行完之后就会释放,而不是等到事务结束.
这样的模式在大插入量的情况下效率底下,在MySQL 5.1.22版本之后,InnoDB存储引擎提供一种轻量级互斥量(原子性变量)的自增长实现机制.
在InnoDB存储引擎中,自增长的值必须是索引列,且必须是索引的第一个列.
InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长模式,可参考
MySQL innodb_autoinc_lock_mode设置
(5). 外键和锁
对于外键,InnoDB存储引擎会自动的加上一个索引,以避免表锁.
对于连接查询,会给父表加读锁.
4. 锁的算法
(1). 行锁的三种算法
- Record Lock:单行锁
- Gap Lock:间隙锁(行与行之间的间隙,用于防止插入数据引起的幻读)
- Next-Key Lock:区间锁,上面两种锁的结合(InnoDB存储引擎对于行的查询都使用这种锁)
当查询的索引含有唯一属性时,InnoDB存储引擎会对Next-Key Lock进行优化,降为Record Lock
对于辅助索引的加锁,会在Next-Key Lock的基础上在给后继的一个间隙加锁
5.锁问题
- 脏读
- 不可重复读
- 丢失更新
6.死锁问题
死锁问题具体可参看操作系统–进程管理
7.锁升级
锁升级:指将当前锁的粒度降低
InnoDB存储引擎不存在锁升级问题。因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的位图的方式