MySQL的锁(一)

按照锁影响范围可分为全局锁,表级锁,行级锁

全局锁:该锁会对整个数据库实例锁上,MySQL提供了一个加全局读锁的方法,命令是Flush tables with read lock ,使用这个命令之后,其他线程的以下语句会被阻塞:DDL,DML;它的典型应用场景是做全量的数据库逻辑备份;但是,让整个库都处于只读的状态,就等同于你要停业务了。但是,在不加锁备份的情况,有新数据写入时,就会造成数据不一致的情况,你备份的那个数据就会参杂了那些新数据,不符合我们的需求。我们也可以通过无锁的方式来保证数据一致,在备份之前开启一个一致性视图,mysql官方自带的逻辑备份工具时mysqldump。当mysqldump使用参数-single-transaction的时候,导数据之前就会启动一个事务。确保拿到一致性视图(基于mysql的默认隔离级别RR),由于这种MVVC的机制,这个备份过程中数据是可以正常更新的。

另外,不要使用set global readonly = true这个命令使得全库只读

表级锁:表级锁又分为两种,一种是表锁,一种是元数据锁。
表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。 另一类表级别锁则是MDL元数据锁,MDL不需要显示使用,在访问一个表的时候会被自动加上,Mysql5.5中引入了MDL,当对一个表做CRUD操作中。加MDL读锁,当要修改表结构时,加MDL写锁

题外话:如何安全地进行DDL?

1.查询当前有没有长事务在执行, information_schema 库的 innodb_trx 表中 ,考虑下先暂停DDL,还是先kill掉这个长事务,一般都是先考虑前者。

2.请求频繁的时候,kill不管用,比较理想的方案是 在alter table语句里面设定等待时间,

ALTER TABLE tbl_name NOWAIT add column …
ALTER TABLE tbl_name WAIT N add column …

行级锁:InnoDB的行锁让Mysql可以支持并发很大的场景,
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议 。
知道了这个设定,对我们使用事务有什么帮助呢?那就是,如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。为了就是缩短锁的时间。

主动死锁检测:
将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的,但是它也是有额外负担的,死锁检测是一个时间复杂度On的操作。

但是建议还是不能把死锁检测关掉,死锁检测可以作为一个兜底方案,我们在前置就能做好许多工作,去规避死锁的发生:1,控制好并发度,客户端做好并发控制。2,数据库层面做好并发,中间件等实现 。根本就是减少InnoDB内部的死锁检测工作。

posted @ 2021-06-06 15:43  hochan_100  阅读(18)  评论(0编辑  收藏  举报