MySQL学习笔记 - 4 - 全局锁与表级锁

258 阅读2分钟

锁种类

  • 全局锁
  • 表级锁
    • 元数据锁(MDL)
    • 表锁
  • 行级锁
    • 行锁
    • 间隙锁
    • next-key lock

行级锁在下一篇文章介绍

全局锁

加锁方式

    flush table with read lock;
  • 加锁后整个库处于只读状态
  • 增删改语句被阻塞,DDL语句被阻塞,更新类事务提交语句被阻塞

典型使用场景

  • 全库逻辑备份
  • 官方自带的逻辑备份工具是mysqldump,通过参数-single-transaction导出数据的时候,会启动一个事务,确保拿到一致性试图,期间可以正常更新数据
  • 需要存储引擎支持可重复读的事务隔离级别,所以FTWRL命名还是有必要的
  • -single-transaction只适用于存储引擎支持事务的表

其他方式

  • set global readonly = true方式也可以设置全库只读
  • 推荐使用FTWRL方式
    • 在主从结构中,readonly的值是用于判断一个库是从库还是主库
    • 执行FTWRL命令,客户端异常断开,MySQL会自动释放全局锁,但set readonly不会

有点像Java中的synchronized和lock

表级锁

表锁

加锁方式

    lock tables ... read/wirte;

可以通过unlock tables主动释放锁,客户端断开连接的时候也会主动释放

  • lock tables ... read

当前线程和其他线程只能在表中读取数据

  • lock tables ... write

当前线程才可以从表中读写数据

元数据锁(MDL)

  • 不需要显示使用,访问表的时候会被自动加上
  • 防止DDL跟DML并发冲突
  • 对表做增删改查的操作,会加上MDL读锁
  • 对表结构做变更操作,会加上MDL写锁
  • 事务中的MDL锁在语句开始执行的时候申请,在语句结束后不会马上释放,等到整个事务提交后再释放

死锁

死锁解决策略

  • 通过参数innodb_lock_wait_timeout设置等待超时时间,默认值为50s
    • 设置等待时间太长,容易导致线上服务不可用
    • 设置等待时间太短,容易会误伤友军
  • 发起死锁检测,设置参数innodb_deadlock_detect = on(默认开启),发现死锁后,主动回滚死锁链中的某个事务,让其他事务继续执行

热点行更新容易导致死锁的问题

  • 如果能从业务上保证不会出现死锁,可以临时把死锁检测关掉(危险操作)
  • 控制并发度(比如限制同一行最多只有10个线程更新)
  • 从设计上优化,将一行变成逻辑上的多行,细化锁粒度,较少死锁检测的CPU消耗

将原本要更新的1行,拆分为n行,那么每次冲突的概率变为原来的1/n