1. 1. 锁分类
  2. 2. 全局锁
  3. 3. 表级锁
    1. 3.1. 表锁
    2. 3.2. 元数据锁(meta data lock, MDL)
    3. 3.3. 安全给小表加字段
  4. 4. 行锁
    1. 4.1. 两阶段锁
    2. 4.2. 死锁和死锁检测

锁分类

  • 全局锁
  • 表级锁
  • 行锁

全局锁

全局锁就是对整个数据库实例加锁
命令

1
flush tables with read lock

使用该命令后其他线程的执行语句都会被阻塞:数据更新语句(数据的增删改)和数据定义语句(建表和修改表结构等)和更新事务的提交语句

应用:全库逻辑备份

  • innodb引擎, mysqldump 使用参数-single-transaction,导数据时会启动一个事务,来确保一致性视图
  • myisam引擎,不支持事务,需要使用FTWRL命令

表级锁

表锁

语句:

1
2
lock tables xxx read/write;
unlock tables;

表锁是最常用的处理并发的方式,而对于innodb这种行锁的引擎,一般不会使用lock tables命令来控制并发,因为锁住整个表的影响太大

元数据锁(meta data lock, MDL)

MDL不需要显示使用,在访问一个表时会自动加上,MDL的作用,保证读写的正确性

  • 在对一个表做增删改查操作,加MDL读锁,当要对表做结构变更操作,加MDL写锁
  • 读锁之间不互斥,可以有多个线程对一张表增删改查
  • 读写锁之间,写锁之间互斥,用来保证变更表结构操作的安全性,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完成后才能开始执行
安全给小表加字段
  1. 需要解决长事务,事务不提交,就会一直占用MDL锁,mysql中的information_schema库中INNODB_TRX表中记录着当前执行中的事务
  2. 变更热点表,在alter table语句里面设置等待时间,如果在等待时间没有拿到也不会阻塞
    1
    2
    alter table xxx nowait add column ...
    alter table yyy wait n add column ...

行锁

行锁是针对数据表中的行记录的锁

mysql行锁是在引擎层自己实现的,并不是所有引擎都支持行锁,如myisam引擎不支持行锁,只能使用表锁,任何时刻只能有一个更新在执行,影响业务并发度

两阶段锁

在innodb事务中,行锁是在需要的时候才加上,但并不是不需要了立刻释放,而是要等到事务结束时才释放

如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放

死锁和死锁检测

死锁:当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态

出现死锁,解决策略:

  • 直接进入等待,直到超时,超时时间可以通过参数innodb_lock_wait_timeout来设置,默认值为50s
  • 发起死锁检测,发现死锁后,主动回滚死锁链条中的某个事物,让其他事物得以继续执行,通过参数innodb_deadlock_detect设置为on,来开启死锁检测

如果所有事务都要更新同一行,这时死锁检测将消耗大量cpu资源,因此出现cpu利用率很高,但每秒执行不了多少事务

解决方案:

  • 控制并发,在数据库服务端控制并发,需要修改mysql源码,要求高
  • 业务上,将更新一行改为逻辑上的多行来减少锁冲突
  • 减少死锁的主要方向,控制访问相同资源的并发事务量

innodb行级锁是通过锁索引记录实现的,如果更新的列没有建索引会锁住整个表的