mysql中有哪些锁

  • 全局锁

    • 要使用全局锁,则要执行这条命令:flush tables with read lock;整个数据库就处于只读状态了

    • 释放全局锁:unlock tables

    • 当会话断开了,全局锁会被自动释放。

    • 使用场景:全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期的不一样。

    • 缺点:加上全局锁,意味着整个数据库都是只读状态。那么如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间,业务只能读数据,而不能更新数据,这样会造成业务停滞。

    • 既然备份数据库数据的时候,使用全局锁会影响业务,那有什么其他方式可以避免?

      • 有的,如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前先开启事务,会先创建 Read View,然后整个事务执行期间都在用这个 Read View,而且由于 MVCC 的支持,备份期间业务依然可以对数据进行更新操作。
    • 备份数据库的工具是 mysqldump,在使用 mysqldump 时加上 --single-transaction 参数的时候,就会在备份数据库之前先开启事务。这种方法只适用于支持「可重复读隔离级别的事务」的存储引擎。

    • InnoDB 存储引擎默认的事务隔离级别正是可重复读,因此可以采用这种方式来备份数据库。但是,对于 MyISAM 这种不支持事务的引擎,在备份数据库时就要使用全局锁的方法。

  • 表级锁

    • 表锁、元数据锁(MDL)、意向锁、AUTO-INC锁

    • 表锁

      • 加表锁语法:lock tables "表名称" read/write

      • 表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。

      • 释放表锁:unlock tables; 退出会话也会释放所有的表锁

      • 不过尽量避免在使用 InnoDB 引擎的表使用表锁 ,因为表锁的颗粒度太大,会影响并发性能,InnoDB 牛逼的地方在于实现了颗粒度更细的行级锁

    • 元数据锁

      • 不需要显式的使用 MDL,因为当我们对数据库表进行操作时,会自动给这个表加上 MDL

        • 对一张表进行 CRUD 操作时,加的是 MDL 读锁

        • 对一张表做结构变更操作的时候,加的是 MDL 写锁

      • MDL 不需要显示调用,那它是在什么时候释放的?

        • MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的。
      • 为什么线程 C 因为申请不到 MDL 写锁,而导致后续的申请读锁的查询操作也会被阻塞?

        • 因为申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁,一旦出现 MDL 写锁等待,会阻塞后续该表的所有 CRUD 操作。
      • 为了能安全的对表结构进行变更,在对表结构变更前,先要看看数据库中的长事务,是否有事务已经对表加上了 MDL 读锁,如果可以考虑 kill 掉这个长事务,然后再做表结构的变更。

    • 意向锁

      • 当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。

      • 意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁( lock tables ... read )和独占表锁( lock tables ... write )发生冲突

      • 如果没有「意向锁」,那么加「独占表锁」时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。

      • 意向锁的目的是为了快速判断表里是否有记录被加锁

    • AUTO-INC锁

      • 表里的主键通常都会设置成自增的,这是通过对主键字段声明 AUTO_INCREMENT 属性实现的。之后可以在插入数据时,可以不指定主键的值,数据库会自动给主键赋值递增的值,这主要是通过 AUTO-INC 锁实现的。

      • 该锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。

      • 在插入数据时,会加一个表级别的 AUTO-INC 锁,然后为被 AUTO_INCREMENT 修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。

      • AUTO-INC 锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。

      • 在 MySQL 5.1.22 版本开始,InnoDB 存储引擎提供了一种轻量级的锁来实现自增。

        • 一样也是在插入数据的时候,会为被 AUTO_INCREMENT 修饰的字段加上轻量级锁,然后给该字段赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁。

        • InnoDB 存储引擎提供了个 innodb_autoinc_lock_mode 的系统变量,是用来控制选择用 AUTO-INC 锁,还是轻量级的锁。

          • 当 innodb_autoinc_lock_mode = 0,就采用 AUTO-INC 锁,语句执行结束后才释放锁;

          • 当 innodb_autoinc_lock_mode = 2,就采用轻量级锁,申请自增主键后就释放锁,并不需要等语句执行后才释放。

          • 当 innodb_autoinc_lock_mode = 1

            • 普通 insert 语句,自增锁在申请之后就马上释放;

            • 类似 insert ... select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放;

          • 当 innodb_autoinc_lock_mode = 2 是性能最高的方式,但是当搭配 binlog 的日志格式是 statement 一起使用的时候,在「主从复制的场景」中会发生数据不一致的问题。

  • 行级锁

    • InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。

    • 普通的 select 语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加行锁,可以使用下面这两个方式,这种查询会加锁的语句称为锁定读。

      • 对读取的记录加共享锁:select ... lock in share mode;

      • 对读取的记录加独占锁:select ... for update;

      • 因为当事务提交了,锁就会被释放,所以在使用这两条语句的时候,要加上 begin、start transaction 或者 set autocommit = 0。

    • 行级锁的类型主要有三类:

      • Record Lock,记录锁,也就是仅仅把一条记录锁上;

      • Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;

      • Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

    • Record Lock

      • Record Lock 称为记录锁,锁住的是一条记录。

      • 记录锁是有 S 锁和 X 锁之分的:

        • 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),但是不可以对该记录加 X 型记录锁(S 型与 X 锁不兼容);

        • 当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁(S 型与 X 锁不兼容),也不可以对该记录加 X 型记录锁(X 型与 X 锁不兼容)。

    • Gap Lock

      • Gap Lock 称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。

      • 间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的

    • Next-Key Lock

      • Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

      • next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。

      • 虽然相同范围的间隙锁是多个事务相互兼容的,但对于记录锁,我们是要考虑 X 型与 S 型关系,X 型的记录锁与 X 型的记录锁是冲突的

    • 插入意向锁

      • 一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。

      • 如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。

      • 插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁。

      • 插入意向锁与间隙锁的另一个非常重要的差别是:尽管「插入意向锁」也属于间隙锁,但两个事务却不能在同一时间内,一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。

相关推荐
HC182580858323 分钟前
“倒时差”用英语怎么说?生活英语口语学习柯桥外语培训
学习·生活
学习路上_write8 分钟前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
喵叔哟9 分钟前
重构代码之移动字段
java·数据库·重构
念白44312 分钟前
智能病历xml提取
数据库·sql·oracle
非概念13 分钟前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
qingy_204616 分钟前
【JavaWeb】JavaWeb入门之XML详解
数据库·oracle
大数据面试宝典20 分钟前
用AI来写SQL:让ChatGPT成为你的数据库助手
数据库·人工智能·chatgpt
努力的小雨25 分钟前
快速上手 KSQL:轻松与数据库交互的利器
数据库·经验分享
Gentle58627 分钟前
labview中连接sql server数据库查询语句
数据库·labview
Gentle58628 分钟前
labview用sql server数据库存取数据到一个单元格
数据库·labview