美文网首页
MYSQL学习笔记4 锁

MYSQL学习笔记4 锁

作者: 夢醒皆涳 | 来源:发表于2022-06-19 15:47 被阅读0次

    全局锁

    命令 Flush tables with read lock (FTWRL)

    • 阻塞
      当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
    • 适用场景 :做全库逻辑备份
    • 不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。
    • 官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。
    • 对于 MyISAM 这种不支持事务的引擎,必须全局锁

    另一种全局锁 不推荐使用

    set global readonly=true 的方式

    • readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库
    • 执行异常断开后不会释放全局锁

    表级锁

    一种是表锁, lock tables … read/write

    • 表锁的语法是线程会造成阻塞,在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式

    表级锁 meta data lock,MDL

    一种是元数据锁(meta data lock,MDL)。

    • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
    • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。同一个表会顺序加字段
    • 事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。MDL读锁与MDL 写锁(ALter改变表结构的),读锁没释放,写锁被阻塞导致,下一个读锁依赖写锁被释放,导致表读写不可用, 使用NOWAIT/WAIT 等待执行,不成功可以重复操作

    行锁

    • 两阶段锁:在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
    • 如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

    死锁

    两个事务互相等待对方先提交会造成死锁

    • 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置,InnoDB引擎默认值是50s。
    • 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
    • 死锁检查会消耗大量CPU,如何解决

    热点数据性能问题

    • 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关闭掉。一般不建议采用
    • 控制并发度,对应相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了。
    • 将热更新的行数据拆分成逻辑上的多行来减少锁冲突,但是业务复杂度可能会大大提高。

    检查死锁

    show engine innodb status

    事务的启动方式

    begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。

    • 第一种启动方式,一致性视图是在执行第一个快照读语句时创建的;
    • 第二种启动方式,一致性视图是在执行 start transaction with consistent snapshot 时创建的。

    事务id

    开启事务会获得一个事务id(自增),数据版本是按照提交时间来排序的


    image.png

    所以 A看到的还是1,一致性原则。
    事务id的排序是 A<B<C
    数据版本的排序是C早于B
    B如果再自己update之前查询,查到的还是1,因为一致性
    但是自己update之后查到的就是3,原因是当前读 再最新的数据版本上执行更新。
    更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。

    事务是如何实现的MVCC呢?

    • 每个事务都有一个事务ID,叫做transaction id(严格递增)
    • 事务在启动时,找到已提交的最大事务ID记为up_limit_id。
    • 事务在更新一条语句时,比如id=1改为了id=2.会把id=1和该行之前的row trx_id写到undo log里,
      并且在数据页上把id的值改为2,并且把修改这条语句的transaction id记在该行行头
    • 再定一个规矩,一个事务要查看一条数据时,必须先用该事务的up_limit_id与该行的transaction id做比对,
      如果up_limit_id>=transaction id,那么可以看.如果up_limit_id<transaction id,则只能去undo log里去取。去undo log查找数据的时候,也需要做比对,必须up_limit_id>transaction id,才返回数据

    相关文章

      网友评论

          本文标题:MYSQL学习笔记4 锁

          本文链接:https://www.haomeiwen.com/subject/gnihvrtx.html