• 全局表、表锁、行锁


    全局锁
    1,全局锁对整个数据库实例加锁,Flush tables with read lock(FTWRL)。
    2,使用全局锁后,数据库处于只读状态,数据更新语句增删改、数据定义语句建表和修改表结构、更新类事务提交语句都会被阻塞。

    3,全局锁应用于全库逻辑备份场景,整库select出来存成文本。
    1)如果在主库上备份,备份期间业务基本停摆;
    2)如果在从库上备份,备份期间不能执行主库同步的binlog,导致主从延迟。
    3)如果不加锁,备份得到的库不是同一个逻辑时间点。

    4,在可重复读隔离级别下开启事务,可确保拿到一致性视图,且备份过程中数据可以正常更新。
    1)官方自带逻辑备份工具mysqldump,当mysqldump使用参数single-transaction,导数据前启动事务。
    2)single-transaction方法适用于所有的表使用支持事务引擎的库。
    3)MyISAM引擎不支持事务,备份中只能使用FTWRL。

    5,全库只读,可以设置set global readonly=true,但不适合用于备份整库。
    1)在一些系统中,readonly还会用来判断主备库,修改global变量影响面更大。
    2)如果备份过程中客户端异常,数据库会一直保持readonly状态,导致整库长时间处于不可写状态,风险太高。
    3)FTWRL客户端异常断开,MySQL会自动释放全局锁,整库可以回到正常更新状态。

    表锁
    1,表级锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL),引擎不支持行锁时使用表级锁。

    2,表锁lock tables …read/write,限制当前线程与其他线程对表的读写。
    1)read t1当前线程只读t1,其他线程只读t1;
    2)write t2当前线程读写t2,其他线程不可读写t2;
    3)其他表不可访问;
    4)与FTWRL类似,unlock tables主动释放锁,客户端断开后会自动释放。

    3,元数据锁不需要显式使用,访问表时自动加上,MDL的作用是保证读写的正确性。
    1)对表做增删改查操作时加MDL读锁,对表结构做变更时加MDL写锁。
    2)读锁之间不互斥,读写及写锁之间互斥,保证变更表结构的安全性。
    3)在事务中执行相关语句,系统自动加上MDL锁,语句结束后不会立即释放,事务提交后才会释放MDL锁。
    4)长事务不提交占着MDL读锁,则写锁阻塞,写锁之后的读锁也被阻塞,导致表不可读写,如果客户端有重试机制,库的线程很容易爆满。
    5)在alter table语句里设置等待时间WAIT N,如果在等待时间里拿到MDL写锁则执行表的变更,如果没拿到写锁也不会阻塞后面的业务,之后可以重试重复这个过程。

    行锁
    1,行锁是由引擎层实现,MyISAM引擎不支持行锁,控制并发时只能使用表锁。

    2,在InnoDB事务中,更新语句时加上行锁,语句结束不释放锁,事务结束后释放行锁,为两阶段锁。

    3,当并发中不同线程出现循环资源依赖,涉及的线程都在等待其他线程释放资源,导致线程进入无限等待状态,称为死锁。出现死锁后,
    1)一种策略是进入等待直到超时,innodb_lock_wait_timeout设置超时时间。
    2)一种策略是发起死锁检测,发现死锁,主动回滚死锁链表中的一个事务,让其他事务可以继续执行,设置参数innodb_deadlock_detect为on,表示开启死锁检测。
    3)innodb_lock_wait_timeout默认值为50s,等待时间较长。设置为小值后,出现死锁可以很快解开,但如果不是死锁,只是锁的等待时间,则会误伤。
    4)采用死锁检测策略,每一个事务被锁,需要检测依赖的其他线程有没有被锁,如此循环,最后判断是否出现了循环等待,即使检测结果没有死锁,但检测过程消耗了大量的CPU资源,虽然CPU利用率很高,每秒却执行不了几个事务。

    4,比较好的思路是开启死锁检测并控制并发量,出现死锁了就回滚,再业务重试,这是业务无损的。
    1)如果关闭死锁检测则可能出现大量超时,这是业务有损的;
    2)控制并发量死锁检测的成本比较低,数据库服务端做好并发控制。

    5,也可以将某一行逻辑修改为逻辑上的多行减少锁冲突。
    1)设计一行数据为多行记录之和,可选随机的一行更新数据,降低冲突概率。
    2)如果有中间件,可在中间件实现,或者修改MySQL源码,对相同行的更新,在进入引擎前排队,则InnoDB内部不会出现大量死锁检测了。
    3)如果事务中需要锁多行,把最可能造成冲突,影响并发的行锁往后放。

    6,例:如果要删除一个表里面前10000行数据:
    1)直接执行delete from T limit 10000,单个语句占用时间长,锁的时间也比较长,如果是大事务会导致主从延迟。
    2)在一个连接中循环执行20次delete from T limit 500,相对较好。
    3)在20个连接中同时执行delete from T limit 500,会人为造成锁冲突。

  • 相关阅读:
    Codeforces Round #818 (Div.2)F(最大流)
    【操作系统】 2.2 调度概念以及调度算法
    [ue5]建模场景学习笔记(6)——必修内容可交互的地形,交互沙(4)
    【线程池】面试被问到线程池参数如何配置时该如何回答
    011:获取上证50的所有股票代码,并下载各个股K线数到excel表中
    java毕业生设计学生用品采购系统计算机源码+系统+mysql+调试部署+lw
    vscode在mac上保存项目文件提示保存失败
    Mongodb出现Error: couldn‘t add user: Could not find role: root@database 解决方法
    八个提升编程体验的VS Code插件
    【pip】查找某个版本的安装包
  • 原文地址:https://blog.csdn.net/mei_true/article/details/127521619