漯河百度做网站电话,制作网站公司选 择乐云seo,网站弄论坛形式怎么做,网站建设公司资料大全锁机制 1. 概述2. 并发事务的不同场景2.1 读-读情况2.2 写-写情况2.3 读-写或写-读情况2.3.1 方案一#xff1a;读事务使用MVCC#xff08;多版本并发控制#xff09;#xff0c;写事务加锁2.3.2 方案二#xff1a;读、写事务均加锁 3. 锁分类3.1 从数据操作类型#xff… 锁机制 1. 概述2. 并发事务的不同场景2.1 读-读情况2.2 写-写情况2.3 读-写或写-读情况2.3.1 方案一读事务使用MVCC多版本并发控制写事务加锁2.3.2 方案二读、写事务均加锁 3. 锁分类3.1 从数据操作类型读锁、写锁3.2 从数据操作粒度表级锁、页级锁、行锁3.2.1 表级锁Table Lock表级别的S锁、X锁意向锁Intention Lock自增锁Auto-Inc Lock元数据锁Meta Data Lock 3.2.2 行锁Row Lock记录锁Record Lock间隙锁Gap Lock临键锁Next-Key Lock插入意向锁Insert Intention Lock 3.2.3 页锁 3.3 从对待锁的态度乐观锁、悲观锁3.3.1 悲观锁3.3.2 乐观锁版本号机制 3.4 从加锁的方式显式锁、隐式锁3.4.1 显式锁3.4.2 隐式锁 4. 死锁4.1 死锁4.2 死锁产生的必要条件4.3 如何处理死锁4.3.1 方式一使用超时机制4.3.2 方式二使用死锁检测机制 4.4 如何避免死锁问题 1. 概述
锁机制是保证事务隔离性的根本计算机通过锁机制协调多进程/多线程并发访问相同资源的问题锁机制保证同一时刻共享资源只能被某一进程/线程访问以此保证数据的一致性和完整性从数据库角度而言共享资源除了硬件资源以外还有表数据为保证表数据的一致性和完整性就必须引入锁机制对并发操作进行控制锁机制会导致锁冲突甚至死锁的发生及其影响并发操作的性能
2. 并发事务的不同场景
2.1 读-读情况
多个事务同时读取相同记录并不会对记录本身造成影响所以无需进行特殊处理
2.2 写-写情况
多个事务均要对相同记录进行修改此时可能会发生“脏写”问题所有隔离级别都解决了“脏写”问题通过对事务加锁的方式实现同一时刻只能允许一个事务执行其他事务排队等待对于锁机制每个事务均对应一个锁结构内存级别与记录关联包括事务信息以及该事务是否需要排队等待等信息 事务对应锁结构中is_waiting有两种取值1is_waitingfalse说明该事务获取锁成功可以继续执行事务2is_waitingtrue说明该事务获取锁失败期望操作的记录已经被加锁当前事务需要排队等待
2.3 读-写或写-读情况
读-写或写-读情况即多个事务中既有数据读取事务也有数据写入事务此时可能会发生“脏读”、“不可重复读”以及“幻读”问题未解决上述并发事务问题MySQL提供两种方案1读事务使用MVCC多版本并发控制写事务加锁2读、写事务均加锁
2.3.1 方案一读事务使用MVCC多版本并发控制写事务加锁
此方案适用于读、写事务不会冲突可同时进行的情况并发性能较高写事务需要对最新数据进行修改所以需要加锁避免其他事务的干扰此情况下读事务只能读取到其他事务已提交的数据因此对于读事务而言其他事务对记录的修改和记录的旧版本不冲突所以可以直接读取旧版本数据MVCC做法1生成ReadView通过ReadView确定符合条件的记录版本记录的历史版本通过undo日志构建2读事务只能看到生成ReadView之前已提交的数据
2.3.2 方案二读、写事务均加锁
此方案适用于读、写事务冲突不能同时进行的情况并发性能较低此情况下读事务需要获取最新数据所以需要避免其他事务的干扰因此需要加锁事务通过对数据记录加锁保证数据一致性避免发生“脏读”、“不可重复读”以及“幻读”问题
3. 锁分类
3.1 从数据操作类型读锁、写锁
读锁readLock也称共享锁Shared LockS Lock写锁writeLock也称排他锁Exclusive LockX Lock对于读事务查询操作可加共享锁或排他锁对于写事务增删改操作可加排他锁读写锁互斥关系 1多个读锁之间不会互斥 2读锁-写锁之间会互斥 3写锁-写锁之间会呼出如果数据已经加锁当前事务无法获取锁则默认进入阻塞状态通过innodb_lock_wait_timeout参数进行控制。MySQL8.0新特性可在加锁操作后添加NOWAIT或SKIP LOCAKED参数执行不同的选择。读事务加锁方式 1读锁select ... for share; 2写锁select ... for updateInnoDB引擎下读写锁既可以加在表上也可加在行上
3.2 从数据操作粒度表级锁、页级锁、行锁
MyISAM引擎只支持表级锁InnoDB引擎支持表级锁、行锁表级锁对应操作粒度较粗行锁对应操作粒度较细操作粒度越细并发性能越好但较耗费资源
3.2.1 表级锁Table Lock
最基本的锁策略不依赖于存储引擎表级锁对应资源开销最小并发性能最低表级锁可避免死锁问题
表级别的S锁、X锁
对于InnoDB引擎而言一般不会使用表级别的S锁、X锁。在某事务执行DDL操作而其他事务在执行DML操作时会触发表锁该过程是在server层通过元数据锁实现的如果仅使用表级别的S锁、X锁则使用MyISAM引擎即可添加表级别的S锁、X锁方式 1添加S锁lock tables 表名 read 2添加X锁lock tables 表名 write释放表锁unlock tables查看表锁show open tables互斥关系
意向锁Intention Lock
InnoDB支持多粒度锁特殊情境下允许行锁和表锁共存意向锁是一种表锁允许和行锁共存意向锁分类意向共享锁IS锁、意向排他锁IX锁当为数据表添加行锁之后数据库会自动为对应数据页或数据表添加相应意向锁如此其他事务想要添加表锁就会进入阻塞状态互斥关系1意向锁之间不互斥2IS锁与表级S锁不互斥其他意向锁与表级S锁或X锁互斥总结
自增锁Auto-Inc Lock
插入数据的方式1简单插入事先知道要插入的数据数量2批量插入事先不知道要插入的数据数量3混合模式插入批量插入数据有些指定了字段序号有些未指定对于数据表如果有字段设置有AUTO_INCREMEN约束则向该表插入数据时会添加表级锁称为自增锁自增锁并发性能较差InnoDB通过innodb_autoinc_lock_mode参数提供不同的锁定机制提高性能 1innodb_autoinc_lock_mode 0(“传统”锁定模式)在此锁定模式下所有类型的insert语句都会获得一个特殊的表级AUTO-INC锁用于插入具有AUTO_INCREMENT列的表。 2innodb_autoinc_lock_mode 1(“连续”锁定模式) MySQL 8.0 之前的默认模式。在这个模式下批量插入仍然使用AUTO-INC表级锁并保持到语句结束。而对于简单插入则通过在 mutex轻量锁 的控制下获得所需数量的自动递增值来避免表级AUTO-INC锁 它只在分配过程的持续时间内保持而不是直到语句完成。 3innodb_autoinc_lock_mode 2(“交错”锁定模式) MySQL 8.0 开始交错锁模式是默认设置。在此锁定模式下自动递增值保证在所有并发执行的所有类型的insert语句中是唯一且单调递增的。但是由于多个语句可以同时生成数字即跨语句交叉编号为任何给定语句插入的行生成的值可能不是连续的。
元数据锁Meta Data Lock
简称MDL锁用于保证表结构与数据的一致性MDL锁在server层实现当某事务要对数据表进行增删改查操作时会自动添加MDL读锁当某事务要对数据表结构进行修改时会自动添加MDL写锁MDL读锁之间不互斥但MDL读-写锁之间是互斥的
3.2.2 行锁Row Lock
也称为记录锁Record Lock即对符合条件的记录加锁MySQL只在引擎层实现了行级锁MyISAM与InnoDB的区别1InnoDB支持事务2InnoDB支持行锁行锁优缺点 1优点锁定粒度小发生锁冲突概率低提高并发性能 2缺点维护锁的开销较大加锁速度慢容易发送死锁问题
记录锁Record Lock
官方名称LOCK_REC_NOT_GAP仅对满足条件的唯一记录进行加锁记录锁也分读锁、写锁读锁之间兼容其他情况互斥
间隙锁Gap Lock
官方名称LOCK_GAP事务隔离级别为可重复读时可通过事务加锁的方式解决脏读、不可重复读以及幻读问题需要注意加锁方式解决幻读问题时会存在一些问题事务读取数据时幻影记录并未存在无法锁定幻影记录数据库引入间隙锁来解决幻读问题即GAP锁的提出仅是为了防止插入幻影记录GAP锁与其他记录锁或间隙锁是不互斥的间隙锁会导致发生死锁问题
临键锁Next-Key Lock
官方名称LOCK_ORDINARY临键锁本质是记录锁和间隙锁的合体既能锁定对应记录也能防止在该记录之前的间隙插入记录事务隔离级别为可重复读时InnoDB引擎默认使用的锁机制即为临键锁
插入意向锁Insert Intention Lock
官方名称LOCK_INSERT_INTENTION;插入意向锁为行锁本质是间隙锁间隙锁可以防止其他事务在锁定的间隙中插入数据插入意向锁为插入数据事务对应的锁结构插入意向锁之间不会互斥插入意向锁和其他锁不互斥
3.2.3 页锁
对数据页进行加锁锁定粒度介于表锁与行锁之间页锁也会发生死锁现象页锁的开销介于表锁和行锁之间锁空间大小是有限的如果某个层级的锁数量超过当前层阈值则会对锁进行自动升级。如此操作会降低内存开销但降低了并发性能
3.3 从对待锁的态度乐观锁、悲观锁
乐观锁、悲观锁只是针对锁的一种设计思想各自有对应的具体实现
3.3.1 悲观锁
思想每次假设最坏的情况即假设每个事务都会修改数据所以每个事务一来就对数据加锁其他事务进行等待数据库中涉及的表锁、行锁等都是悲观锁的具体实现悲观锁适用于频繁写操作的情况
3.3.2 乐观锁
思想对并发事务保持乐观态度认为同一数据的并发事务并不会经常发生因此事务刚开始并不会进行加锁而是真正要修改数据时才去判断是否发生了并发冲突乐观锁在程序级别通过代码实现而不会通过数据库底层乐观锁的实现方案1版本号机制2CAS机制乐观锁不会发生死锁问题乐观锁适用于频繁读操作的情况
版本号机制
对数据添加版本号字段versionversion有初始值事务在操作数据时同时获取数据对应版本号只有当事务版本号version‘大于最开始获取的数据版本号version时才能完成数据修改的提交
3.4 从加锁的方式显式锁、隐式锁
3.4.1 显式锁
通过特定语句加的锁称为显式锁如
3.4.2 隐式锁 4. 死锁
4.1 死锁
两个事务均持有对方需要的锁且在等待对方释放锁而事务自身均不会释放自己持有的锁。此时两个事务进入循环等待均无法继续执行。产生死锁的关键在于两个事务加锁的顺序不一致
4.2 死锁产生的必要条件
至少存在两个事务每个事务都持有锁并需要申请新的锁锁资源同时只能被同一个事务持有事务之间因为持有锁和申请锁导致彼此循环等待
4.3 如何处理死锁
4.3.1 方式一使用超时机制
事务如果无法成功获取锁则进入等待直到等待超时超时时间通过innodb_lock_wait_timeout参数设置如果事务等待超时则将其回滚缺点不适用于在线任务
4.3.2 方式二使用死锁检测机制 InnoDB使用wait-for graph算法主动进行死锁检测 事务一旦无法成功获取锁则主动进行死锁检测检测是否是自己的加入导致死锁的发生 一旦检测到死锁InnoDB选择回滚undo量最小的事务其他事务继续执行 缺点对于并发事务量较大的业务死锁检测耗时较大
4.4 如何避免死锁问题 参考《尚硅谷康师傅》