全局锁
在备份过程中整个库完全处于只读状态
- Flush tables with read lock (FTWRL):当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句
- set global readonly= true
readonly与FTWRL区别
- 一是,在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,我不建议你使用
- 二是,在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。
让整库都只读,听上去就很危险
- 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
- 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的 binlog,会导致主从延迟。
MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
表锁
表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放
元数据锁MDL
1)MDL读锁,保证的是表结构不能修改,而与表数据无关,它是可以CRUD的。
2)MDL写锁,保证的是表结构不能被并行修改,同时表数据也不能读了。
3)MDL锁最重要的作用,就是防止 DDL和DML的并发冲突,也就是防止线程2在修改表A的表结构时,线程1在对表A查询的这种情况。这一点也就是通过MDL写锁来解决的。
4)读锁的作用是提高访问效率,这个体现了读写分离的思想。
5)MDL读写锁中,如果存在读锁,那么写锁需要等待读锁释放,而存在写锁时,读锁需要等待写锁释放.
- 事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。
行锁
InnoDB 是支持行锁的,这也是 MyISAM 被 InnoDB 替代的重要原因之一。如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁的申请时机尽量往后放。
两段锁协议:在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议
如果update的列没建索引,即使只update一条记录也会锁定整张表:没有加索引,则直接走主键索引进行查询匹配,符合条件的加上锁,这样就相当于表级锁了,会导致全表扫描(表锁),因为没有命中索引情况下,RR会锁表,RC会锁行
问题
1.两阶段锁的概念是什么? 对事务使用有什么帮助?
行锁并不是不需要了立即释放,需要事务提交才释放;
2.死锁的概念是什么? 举例说明出现死锁的情况.
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态。
3.死锁的处理策略有哪两种?
1、通过参数 innodb_lock_wait_timeout 根据实际业务场景来设置超时时间,InnoDB引擎默认值是50s。
2、发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑(默认是开启状态)
4.等待超时处理死锁的机制什么?有什么局限?
在 InnoDB 中,innodb_lock_wait_timeout 的默认值是 50s,意味着如果采用第一个策略,当出现死锁以后,第一个被锁住的线程要过 50s 才会超时退出,然后其他线程才有可能继续执行。对于在线服务来说,这个等待时间往往是无法接受的
5.死锁检测处理死锁的机制是什么? 有什么局限?
每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是 O(n) 的操作。假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。
6.有哪些思路可以解决热点更新导致的并发问题?
降低并发度 1. 拆行,一行拆多行 2. Server 层限流,即同一时间进入更新的线程数 3. 关闭死锁监测(关闭的弊端是可能超时较多)