MySQL:行锁、表锁、乐观锁、悲观锁、读锁、写锁

1、锁的分类

  1.1从对数据操作的类型来分

    读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。    

      结论1:
      --如果某一个会话 对A表加了read锁,则 该会话 可以对A表进行读操作、不能进行写操作; 且 该会话不能对其他表进行读、写操作。
      --即如果给A表加了读锁,则当前会话只能对A表进行读操作。

      结论2:
      会话0给A表加了锁;其他会话的操作:a.可以对其他表(A表以外的表)进行读、写操作
      b.对A表:读-可以; 写-需要等待释放锁。、

      某回话给某个表加了读锁,所有的回话都能对该表进行读操作,不能进行写操作,除非该会话释放读锁。

    写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。    

      当前会话(会话0) 可以对加了写锁的表 进行任何操作(增删改查);但是不能 操作(增删改查)其他表
      其他会话:对会话0中加写锁的表 可以进行增删改查的前提是:等待会话0释放写锁

2.2锁粒度划分。

一般分为:行锁、表锁、库锁

(1)行锁:访问数据库的时候,锁定整个行数据,防止并发错误。 如InnoDB存储引擎使用行锁

(2)表锁访问数据库的时候,锁定整个表数据,防止并发错误。 如MyISAM存储引擎使用表锁

行锁 和 表锁 的区别:

  • 表锁: 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突概率高,并发度最低
  • 行锁: 开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高

加行锁的情况:
精确查询(使用索引):
当查询条件使用了索引(如主键、唯一索引或普通索引),InnoDB 会对符合条件的行加行锁。
例如:SELECT * FROM table WHERE id = 1 FOR UPDATE; 会对 id = 1 的行加行锁。
范围查询(使用索引):
当查询条件是一个范围(如 BETWEEN、>、<),InnoDB 会对范围内的行加行锁,并使用间隙锁(Gap Lock)或临键锁(Next-Key Lock)防止幻读。
例如:SELECT * FROM table WHERE id > 10 AND id < 20 FOR UPDATE; 会对 id 在 10 到 20 之间的行加行锁和间隙锁。
更新或删除操作(使用索引):
当 UPDATE 或 DELETE 语句使用了索引,InnoDB 会对符合条件的行加行锁。
例如:UPDATE table SET name = 'test' WHERE id = 5; 会对 id = 5 的行加行锁。

加表锁的情况
全表扫描(无索引):
当查询条件没有使用索引,InnoDB 会进行全表扫描,并可能对整个表加锁。
例如:SELECT * FROM table WHERE name = 'test' FOR UPDATE; 如果 name 列没有索引,InnoDB 可能会加表锁。
锁升级:
当需要锁定的行数过多(例如大量行被修改或删除),InnoDB 可能会将行锁升级为表锁以提高效率。
显式表锁:
使用 LOCK TABLES 语句显式请求表锁时,InnoDB 会加表锁。

总结
行锁:查询条件使用了索引,或对少量行进行操作时。
表锁:查询条件未使用索引,或需要锁定大量行时。
在实际使用中,尽量为查询条件添加索引,以避免表锁并提高并发性能。

 

2. 3  补充   悲观锁 和 乐观锁

(1)悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

(2)乐观锁: 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

(3)悲观锁 和 乐观锁的区别:

  • 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能
  • 乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

小结:

MySQL5.5 版本以前默认引擎是MyISAM表级锁的锁模式 。不支持事务

5.5以后默认引擎是InnoDB行级锁的锁模式。支持事务
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,
在执行更新操作(DML)前,会自动给涉及的表加写锁。
所以对MyISAM表进行操作,会有以下情况:
a、对MyISAM表的读操作(加读锁),不会阻塞其他进程(会话)对同一表的读请求,
但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
b、对MyISAM表的写操作(加写锁),会阻塞其他进程(会话)对同一表的读和写操作,
只有当写锁释放后,才会执行其它进程的读写操作。

 

posted @   好记性不如烂笔头=>  阅读(3982)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示