mysql的锁

MySQL的锁mysql

  • 全局锁:对数据库实例加锁
    • MySQL提供了一个加全局读锁的方法:Flush tables with read lock(FTWRL)
    • 使用场景:作全库逻辑备份。
    • 官方自带的逻辑备份工具mysqldump,使用时带上参数-single-transaction,导数据以前就会启动一个事务,来确保拿到一致性视图。因为MVCC的支持,这个过程是能够正常更新的。
    • FTWRL用在MyISAM这种不支持事务的引擎上。
    • single-transaction方法只能用在全部的表都使用事务引擎的库。
    • set global readonly=true也可让全库进入只读状态,可是不推荐用在全库备份的场景下。
  • 表级锁
    • 分类
      • 表锁
        • 语法
          • 加锁:lock tables ... read/write
          • 释放锁:unlock tables
        • 使用场景:非事务引擎
      • 元数据锁(meta data lock,MDL)
        • MySQL5.5版本中引入了MDL,分为MDL读锁和MDL写锁。
        • 不须要显式使用,在访问一个表的时候会被自动加上。
        • 事务中的MDL锁,在语句开始时申请,可是在语句结束后不会立刻释放,而是等整个事务提交后再释放。对于长事务,事务不提交,就会一直占着MDL锁(重要)
        • 做用:保证读写的正确性。
        • 规则:
          • 读锁之间不互斥,能够有多个线程同时对一张表(应该指的是表的元数据)增删改查。
          • 读写锁之间、写锁之间是互斥的,用来保证变动表结构操做的安全。若是两个线程要同时给一个表加字段,其中一个要等另外一个执行完才能开始执行。
        • 避坑指南
          • 给一个小表加个字段致使整个库挂了!!!如何安全地给小表加字段?
            • 2个知识点:
              • 给一个表加字段、或者修改字段、或者加索引,须要扫描全表的数据。
              • 事务中的MDL锁,在语句开始时申请,可是在语句结束后不会立刻释放,而是等整个事务提交后再释放。
            • 解决方法
              • 解决长事务:事务不提交,就会一直占着MDL锁。
              • 查询information——schema库的innodb_trx表中正在执行的长事务,暂停长事务,而后再修改表。
              • 对与热点表的修改,kill事务的方式很差用,能够在alter table 语句里设定等待时间。若是在指定的等待时间里拿到了MDL锁最好,拿不到也不会阻塞后面的业务语句,先放弃。以后开发人员或者DBA再重试命令。
              • MariaDB和AliSQL目前都支持DDL NOWAIT/WAIT n 这个语法
  • 行锁
    • 定义:针对数据库表中行记录的锁。
    • MySQL的行锁是引擎层由各个引擎本身实现的。MyISAM引擎不支持行锁。
    • 两阶段锁协议:在InnoDB事务中,行锁是在须要的时候才加上的,但并非不须要了就马上释放,而是等到事务结束才释放。
    • 建议:若是事务中须要锁多个行,要把最可能形成锁冲突、最可能影响并发度的锁尽可能日后放。
    • 死锁和死锁检测
      • 解决死锁的策略
        • 一:直接进入等待,直到超时,超时时间经过参数innodb_lock_wati_timeout来设置。InnoDB中,这个值默认是50s,这个值对于在线服务来讲,是没法接受的。把这个值设置成一个小的值也是不合理的。因此不推荐这个方式来解决死锁。
        • 二:发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其余事务得以继续执行。设置参数innodb_deadlock_detect=on。InnoDB中,这个值默认就是on,也就是说InnoDB会自动死锁检测。
          • 每一个新来的被堵住的线程,都要判断会不会因为本身的加入致使了死锁。这是一个时间复杂度为O(n)的操做。
          • 当有1000个线程要同时更新同一行,那么死锁检测操做就是(1000*1000)百万量级的。虽然最终检测的结果是没有死锁,可是这期间消耗大量的CPU资源。
      • 如何解决由热点行更新致使的性能问题呢?
        • 思路一:临时把死锁检测关掉(前提是确保这个业务必定不会出现死锁)
        • 思路二:控制并发度。
          • 客户端作并发控制(当客户端多的时候不太可行)
          • 在中间件中实现,或者修改MySQL源码,对于向同行的更新,在进入引擎前排队。这样InnoDB内部就不会有大量的死锁检测工做了。
          • 从设计上作优化:将一行改为逻辑上的多行来减小锁冲突。(须要根据业务逻辑作详细设计)
相关文章
相关标签/搜索