全局锁,表锁,行锁

锁的范围越大,并发性就越差。但是这并不意味锁定范围做小的锁就好了,技术还是围绕业务场景展开的,这边写出一点对全局锁 表级锁 行锁的理解

全局锁

当需要让整个数据库都处于只读状态的时候,可以使用下面这个命令,之后的其他数据更新,数据定义语句全部会被堵塞住

1
FLUSH TABLE WITH READ LOCK

它的应用场景是做全库的逻辑备份,但是一般没人会真的这样做。因为这样做会有一堆的风险,主库这样做业务GG,从库这样做主从业务延迟。

在讲到事务隔离级别,时有一个可重复读可以解决备份时的逻辑问题,mysql自带的mysqldump工具中加上-single-transaction在导出数据前就会启动一个事务,来确保一致性视图。但是需要注意这个方法只适用支持事务的数据库引擎

表级锁

名称 互斥
读锁 X Y X
写锁 X X Y

表锁

1
2
3
lock tables ... read/write

unlock tables

元素锁

不需要显式操作,在访问一个表的时候自动加上,meatadate lock的作用是保证读写的正确性,在5.5的版本做正删改操作的时候MDL加读锁,对表做结构变更MDL加写锁

行锁

InnoDB的行锁提高了数据库的并发性(锁的范围小),但是一些错误的使用还是会造成致命的后果下面介绍下InnoDB里的二阶段锁协议及如何在事务中更高效的支持并发。

二阶段锁协议

步骤 语句一 语句二
1 BEGIN
2 UPDATE zjj_tags set tid =99 WHERE id = 6032 BEGIN
3 UPDATE zjj_tags set tid =100 WHERE id = 6032
4 UPDATE zjj_tags set tid =1 WHERE id = 6033 堵塞
5 COMMIT 等待
6 id=6032,tid=99 COMMIT
7 id=6032,tid=100

所谓的二阶段锁协议就是把锁分为了加锁和解锁的阶段,从上面的执行表格可以看出语句一在执行时事务未提交,语句二的事务是处于堵塞状态的,这就是所说的二阶段锁协议。对于事务而言,事务开始处于加锁状态事务结束处于解锁状态。只有满足二段锁协议的数据库,并发调度的事务才是可以串行化

优化

通过上述我们知道了二阶段锁协议由此可见如果想最快的提升事务的性能我们可以把容易造成冲突的语句尽量放到事务最后执行,这样可以缓解事务加锁对于并发请求的等待

死锁

死锁就是事务和事务间的依赖造成的死循环,解决死锁的方法有2种

  • 进入死锁等待超时innodb_lock_wait_timeout 默认50秒
  • 发起死锁检查innodb_deadlock_detect 5.7后开始自持默认开启

我们不能手动的吧innodb_lock_wait_timeout调太小,因为我们不知道事务是否会在我们认为的一个理想状态下提交。但是innodb_deadlock_detect有一定的性能消耗。在高并发的环境下我们可以做几种选择,在保证无死锁的状态下关掉innodb_deadlock_detect死锁检测。或者用中间件控制并发量

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~