概述:在并发访问时,解决数据访问的一致性,有效性问题,分为全局锁,表级锁,行级锁
全局锁:对整个数据库实例加锁,加锁后整个实例就处于只读状态性能较差,数据逻辑备份时候使用
表级锁:操作锁住整张表,锁的粒度较大,发生所冲突的概率高; 表锁,元数据锁,意向锁
行级锁:操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低
行锁,间隙锁,临键锁
全局锁
全局锁就是给整个数据库实例加锁,加锁后整个时实例都处于只读状态,后续的DML,DDL 语句以及更新操作的事务提交语句都被阻塞
目前的情况是违反了数据的一致性的,因为首先备份了tb_stock ,备份之后用户下单,此时【库存表数据减少】,然后生成订单,备份tb_order表,然后插入订单日志,备份tb_orderlog,此时【只有库存表是老数据,其他表都是新数据】
解决方案:全局锁;
先将数据库锁住,然后执行指令mysqldump【mysql提供的用于数据备份的工具】,然后DML,DDL请求被阻塞,但是DQL可以正常请求,直到生成一个.sql后缀的文件
如何加锁?如何释放锁?
一致性数据备份
myslqdump -uroot -p1234 db01 > D:/db01.sql ,这并不是一个sql语句,因此不在mysql>中执行,而是在windows的命令行中执行,因为当前连接的是远程数据库,因此还要指定远程数据库端口号
数据库加上全局锁,是一个比较重的操作,存在以下问题:
1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆
2.如果是在从库上备份,那么在备份期间,,从库不能执行主库同步过来的二进制日志(binlog) ,会导致主存延迟
解决方法:
表级锁
每次操作锁住的是整张表。锁的粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM,InnoDB,BDB等存储引擎中。
1.表锁分为:
1.表共享读锁(read lock)
2.表共享写锁(write lock)
当给一张表加了读锁,那么会阻塞其他客户端的写操作,而不会阻塞读操作
当给一张表加了写锁,那么其他客户端的写操作以及读操作都被阻塞,只有自己能写和读
语法:
1.加锁 lock tables 表名.... read/write //可以批量上锁
2.释放锁: unlock tables /客户端断开连接
2.元数据锁
MDL加锁过程是系统自动控制的,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL的冲突,保证读写的正确性
SHARED_READ和SHARED_WRITE兼容是什么?
比如说两个客户端A,B;A开启一个事务,第一步执行读操作【正常执行】,然后B也开启一个事务,第一步执行读操作,然后B第二步执行写操作,即使事务A并未提交,数据库数据仍然修改了
但是如果在事务A未提交的时候,另一个客户端B执行alter 修改表结构【不会执行成功,会被阻塞】,直到事务A提交
3.意向锁
此时存在效率极低的问题,因为线程B检查表中是否有行锁需要对每一行进行检查
优化:使用意向锁,当线程A加上行锁之后,再给整张表加上一个意向锁,当线程B加锁与意向锁兼容,那可以直接加锁,否则线程B阻塞;
多个事务可以同时获取标记别的意向锁(IS或者IX)
- 意向锁是兼容性的:
-
IS
锁表示“本事务打算/正在某些行上加 S 锁”。IX
锁表示“本事务打算/正在某些行上加 X 锁”。- 多个事务可以同时持有同一个表的
IS
锁或IX
锁 (它们兼容),只要它们操作的是不同的行。
意向锁是存储引擎(InnoDB)内部用于优化行锁-表锁冲突检测的机制,而元数据锁是MySQL-Server用于强制保证数据结构与数据操作一致性的全局机制
行级锁
行级锁,每次操作锁住对应的行数据。锁的粒度最小,发生锁冲突的概率最低,并发度高。应用在InnoDB存储引擎中。
InnoDB的数据是基于索引组织的【行数据是基于聚集索引存储的所以这里说数据是基于索引组织的】,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为三类
1.行锁 (RECORD LOCK) :锁定单个行记录的锁,防止其他事务事务对此行数据进行update和delete ,在RC。RR隔离级别下都支持
InnoDB实现了以下两种类型的行锁:
1.共享锁(S): 允许一个事务去读一行,组织其他事务获得相同数据集的排他锁
2.排他锁 (X):允许获取排他锁的事务更新数据,阻止其他事务获取相同数据集的共享锁和排他锁
注意执行update/ insert /delete的时候自动加锁
2.间隙锁(GAP LOCK) : 锁顶索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读.在RR隔离级别下支持
间隙锁的核心作用:防止幻读的核心机制:
幻读场景:事务A读取某个范围内满足条件的行(例如 where age between 12 and 20 ),事务B 此时插入一条符合条件的全新数据(age = 13) 并提交。随后事务A再次以相同条件读取【此时事务A未提交,是在一个事务内呢查询到的数据不一致】,发现多了一条之前不存在的数据(幻行)
解决方案:当事务A执行范围查询的时候(即使是查询操作,在RR级别下也可能加锁)或更新/删除/插入操作需要顶点插入点时,InnoDB不仅仅会给已经找到的是记录加锁(行锁-record lcok),还会给记录与记录之间的间隙 (Gap) 加锁。此时事务B不能执行插入操作,会被阻塞,直到事务A提交或回滚,阻止了事务B造成的事务A的幻读问题
注意:必须为唯一索引,普通索引是不可以的;当执行update stu set age = 10 where id = 5;的时候虽然没有id为5的数据但是还是执行成功了,此时是在id=3和8之间的空隙加了一个间隙锁;此时如果其他客户端想要插入id为【3-8】的数据会被阻塞
注意临键锁的概念锁住的是数据与数据前面的间隙,因为是普通索引所以她不能保证只查到一个id,可能存在多个id,所以他会不停的向右遍历,直到一个不满足查询条件的字段值,所以符合条件的都是加的临键锁,只有【最后一个不符合条件的数据】和【第一个不符合条件数据】之间加的是间隙锁
在数据库系统中,当在唯一索引(如主键或唯一约束列)上进行范围查询(例如 WHERE id BETWEEN 10 AND 20)时,查询执行器会扫描索引直到找到第一个不满足范围条件的值,然后立即停止扫描。这个过程避免了不必要的磁盘 I/O 或数据访问,提升了查询效率。例如:
假设一个表有一个唯一索引的 id 列,数据值为 5, 10, 15, 20, 25。
如果执行查询 SELECT * FROM table WHERE id BETWEEN 10 AND 20,引擎会从 id=10 开始扫描:
它依次访问 10(满足)、15(满足)、20(满足,因为 BETWEEN 是闭区间),直到 25(不满足条件,大于20)。
扫描在 25 停止,不会继续到 25 之后的值(如 30),节省了资源。
这种方法确保了查询只处理相关范围,减少扫描的开销。