mysql 全局锁

发布时间 2023-11-20 22:15:12作者: 若-飞

1.全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是Flush tables with read lock ,即FTWRL。

MySQL全局锁是一种数据库级别的锁,用于在执行特定操作时阻塞其他会话对数据库的访问。当全局锁被获取时,其他会话的读写操作将被暂停,直到全局锁被释放。

全局锁适用于需要对整个数据库进行一致性操作或维护任务的场景,例如备份、数据库迁移、表结构变更等。通过获取全局锁,可以确保在执行这些操作期间,数据库保持在一个一致的状态,避免数据不一致或损坏。

全局锁的获取通过执行FLUSH TABLES WITH READ LOCK语句来实现。该语句会获取一个全局只读锁,并阻塞其他会话对数据库的写操作,但允许其他会话的读操作继续进行。在获取全局锁后,可以执行需要的操作,然后使用UNLOCK TABLES语句来释放全局锁。

以下是一个示例,演示如何使用全局锁:

sql
-- 获取全局锁
FLUSH TABLES WITH READ LOCK;

-- 执行需要的操作,例如备份数据库
-- ...

-- 释放全局锁
UNLOCK TABLES;

在上述示例中,通过执行FLUSH TABLES WITH READ LOCK语句获取了全局锁。在获取全局锁期间,其他会话的写操作将被阻塞,但读操作仍然允许进行。在执行需要的操作(例如备份数据库)后,使用UNLOCK TABLES语句释放全局锁,从而恢复正常的数据库访问。

需要注意的是,获取全局锁会对数据库的正常运行产生影响,因为它会阻塞其他会话的写操作。所以,在使用全局锁时需要谨慎,并确保在必要时使用,并在操作完成后及时释放全局锁,以允许其他会话继续正常操作数据库。

当你需要让整个库处于只读状态的时候,可以使用这个命令,之后将会禁止该数据库中的数据更新和表的结构修改操作,一般在对整个库进行逻辑备份时使用。

在对整个库进行逻辑备份时,如果不加全局锁,由于数据库的备份不可能一瞬间完成,那么将可能造成最终数据不一致的问题。

比如有一个用户余额表,一个商品表,逻辑是用户先在余额表中扣款,然后在商品表中添加购买的商品。假设在此处操作的余额表扣款之前发起了数据库备份,首先备份的余额表,那么此时备份的余额表并没有在此次交易中扣款,在备份余额表之后,余额表发起了扣款,并且商品表增加了商品信息,此时备份到商品表,那么备份的商品表中增加了本次交易的商品。最终结果就是在备份的数据之中,余额表并没有扣款,但是商品表中增加了商品,这样商家就承担了损失。而如果是先添加商品,然后扣款的话,那么最终可能导致商品没有添加,但是被扣了款,那么用户就会来找你了!

也就是说,不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。

对于整个数据库加全局锁的确会非常的影响性能:

  1. 整个数据库变得只读,那么正常的业务逻辑肯定会受到影响,业务基本上就得停摆;

  2. 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;

  3. 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。

对于事务性执行引擎来说,还可以使用官方自带的逻辑备份工具是mysqldump,他利用了MVCC的一致性视图的原理,当mysqldump使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图,而由于MVCC的支持,这个过程中数据是可以正常更新的。

对于MyISAM这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用FTWRL命令而不能使用mysqldump了。

2.还有一种方法,那就是使用set global readonly=true的方式,

让整个数据库变得只读,但这种方式并不推荐:

  在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此修改 global 变量的方式影响面更大,不建议适用。

  在异常处理机制上有差异,如执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。

 

3. 总结

记住,业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)。不论是哪种方法,一个库被全局锁上之后,你要对里面任何一个表做更改操作,都会被锁住的。