锁的分类

  • 操作类型分类:
    • 读锁 : 针对同一份数据,多个读操作可以同时进行而互不影响
    • 写锁 : 当前写操作没完成前,会阻断其他写锁和读锁
  • 操作粒度分:

    • 表锁
      • 特点:偏向MyISAM引擎,开销小,加锁快;无死锁,锁粒度大,发生锁冲突的概率高,并发度低
    • 行锁

      常用命令

  • 手动加锁: lock table 表名字 read(write) , 表名字2 read(write) … ;

  • 释放锁: unlock tables;
  • 查看表上加过的锁 show open tables;image.png

小节

  1. 对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一张表的读操作,但会阻塞对同一张表的写操作,需要等待读锁释放后,才会执行其他进程的写操作
  2. 对MyISAM表的写操作(加写锁),会阻塞其他进程对同一张表的读写操作,只有当写锁释放,才会执行其他进程的读写操作
  3. 简而言之:读锁阻塞写,写锁阻塞读写

    表锁分析(偏向MyISAM)

    image.png

行锁分析(偏向InnoDB)

  • 特点:开销大,加锁慢;会出现死锁,锁粒度小,锁冲突概率低,并发度高
  • InnoDB 和 MyISAM最大区别:支持事务,行锁 (由于行锁支持事务)
  • 并发事务带来的问题:
    • 更新丢失
    • 脏读: 事务A读到事务B尚未提交的数据
    • 不可重复读:事务A再次读取之前的数据发生了改变,即事务A读到了事务B已提交的数据
    • 幻读:事务A读到了事务B新提交的数据
  • 隔离级别
    • 未提交读(Read uncommited) :
    • 已提交读(Read commited):
    • 可重复读(Repeatable read) : MySQL的默认级别
    • 可序列化(Serializable):
    • image.png
    • 查看当前事务隔离级别:show variables like ‘tx_isolation’;
  • 索引失效导致行锁变表锁
  • 间隙锁的危害
    • 什么是间隙锁:当我们使用范围条件检索数据,并请求共享排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,对于键值在范围内但不存在的记录,叫做间隙(比如数据库本来存在id为1、3、4、5的记录,然后事务A范围更新1~5的记录,此时如果另一个事务插入id = 2的记录,在事务A调教事务之前会被阻塞)
    • InnoDB也会对这个间隙加锁,这种锁机制称为间隙锁(Next-Key锁)
  • 如何锁定某一行?
    • select * from A where id = ? for update 单独锁定某一行
  • 优化建议:
    • 尽可能让所有数据检索通过索引完成,避免行锁变表锁
    • 合理设计索引,缩小锁的范围
    • 尽可能较少索引条件,避免锁间隙
    • 控制事务大小,减少锁定资源量和时间长度
    • 尽可能低级别事务隔离