全局锁、表级锁和行锁
锁分类
- 全局锁
- 表级锁
- 行锁
全局锁
全局锁就是对整个数据库实例加锁
命令1flush tables with read lock
使用该命令后其他线程的执行语句都会被阻塞:数据更新语句(数据的增删改)和数据定义语句(建表和修改表结构等)和更新事务的提交语句
应用:全库逻辑备份
- innodb引擎, mysqldump 使用参数-single-transaction,导数据时会启动一个事务,来确保一致性视图
- myisam引擎,不支持事务,需要使用FTWRL命令
表级锁
表锁
语句:12lock tables xxx read/write;unlock tables;
表锁是最常用的处理并发的方式,而对于innodb这种行锁的引擎,一般不会使用lock tables命令来控制并发,因为锁住整个表的影响太大
元数据锁(meta data lock, MDL)
MDL不需要显示使用,在访问一个表时会自动加上,MDL的作用,保证读写的正确性
- 在对一个表做增删改查操作,加MDL读锁,当要对表做结构变更操作,加MDL写锁
- 读锁之间不互斥,可以有多个线程对一张表增删改查
- 读写锁之间,写锁之间互斥,用来保证变更表结构操作的安全性,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完成后才能开始执行
安全给小表加字段
- 需要解决长事务,事务不提交,就会一直占用MDL锁,mysql中的information_schema库中INNODB_TRX表中记录着当前执行中的事务
- 变更热点表,在alter table语句里面设置等待时间,如果在等待时间没有拿到也不会阻塞 12alter table xxx nowait add column ...alter table yyy wait n add column ...
行锁
行锁是针对数据表中的行记录的锁
mysql行锁是在引擎层自己实现的,并不是所有引擎都支持行锁,如myisam引擎不支持行锁,只能使用表锁,任何时刻只能有一个更新在执行,影响业务并发度
两阶段锁
在innodb事务中,行锁是在需要的时候才加上,但并不是不需要了立刻释放,而是要等到事务结束时才释放
如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放
死锁和死锁检测
死锁:当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态
出现死锁,解决策略:
- 直接进入等待,直到超时,超时时间可以通过参数
innodb_lock_wait_timeout
来设置,默认值为50s - 发起死锁检测,发现死锁后,主动回滚死锁链条中的某个事物,让其他事物得以继续执行,通过参数
innodb_deadlock_detect
设置为on,来开启死锁检测
如果所有事务都要更新同一行,这时死锁检测将消耗大量cpu资源,因此出现cpu利用率很高,但每秒执行不了多少事务
解决方案:
- 控制并发,在数据库服务端控制并发,需要修改mysql源码,要求高
- 业务上,将更新一行改为逻辑上的多行来减少锁冲突
- 减少死锁的主要方向,控制访问相同资源的并发事务量
innodb行级锁是通过锁索引记录实现的,如果更新的列没有建索引会锁住整个表的