MySQL数据库只读锁,维护期间锁定站点写入
维护窗口为什么要锁写
站点维护、
数据迁移或版本升级时,
如果有用户还在往数据库写数据,
很容易出现数据不一致、
主从不同步甚至丢数据的情况。902. MySQL数据库只读锁,
维护期间锁定站点写入,
说的就是在维护窗口内把数据库改成只读状态,
让所有写入操作暂停,
保证维护前后数据完整。
这篇教程面向零基础运维,假设你有一台Linux服务器、MySQL 5.7或8.0,并且有root或具备SUPER权限的账号。
跟着做,你能学会两种锁写方式,知道什么时候用哪种,也能处理常见的锁等待和连接断开问题。
---
先分清两种只读锁
MySQL里锁写入不等于锁所有操作,下面两种方式效果不同,别混用。
read_only全局变量:设置后普通用户只能读,但拥有SUPER权限的账号仍然可以写。
适合不想完全断掉管理操作的维护场景。
FLUSH TABLES WITH READ LOCK:简称FTWRL,会关闭所有打开的表并加全局读锁,任何账号都不能写,连SUPER也不行。
适合备份、主从切换这类需要绝对静止的场景。
判断条件:如果你还要在维护期间执行DDL或数据修正,选read_only;
如果只是备份或迁移,选FTWRL。
---
操作步骤:设置只读并保留会话
第一步:登录MySQL并查看当前状态
mysql -uroot -p
进入后执行:
SHOW VARIABLES LIKE 'read_only';
默认是OFF。
如果已经是ON,说明之前有人设置过,先确认是否还需要。
第二步:设置全局只读
SET GLOBAL read_only = ON;
执行后普通用户的INSERT、UPDATE、DELETE会立刻报错:
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
这个报错是正常的,说明锁写生效了。
第三步:验证只读是否生效
新开一个终端,用普通账号连接,尝试写入:
INSERT INTO test_table (id) VALUES (1);
如果报1290错误,说明只读锁已生效。
第四步:维护完成后解除只读
SET GLOBAL read_only = OFF;
再用普通账号测试写入,能成功就说明站点恢复。
注意:read_only不会阻止SUPER账号写入,所以维护期间不要用root去改业务表,否则可能破坏数据一致性。
---
更严格的FTWRL锁写方式
如果维护期间要求所有写入完全停止,包括SUPER账号,用FTWRL。
关键点:FTWRL执行后,当前会话必须保持连接,一旦断开锁自动释放。
所以不要在mysql命令行里执行完就退出。
推荐做法:另开一个终端执行备份或维护操作,原会话保持不动。
FLUSH TABLES WITH READ LOCK;
执行成功后,当前会话不要输入exit,也不要关闭终端。
验证方式:新开终端用任意账号(包括root)尝试写入,应该都会报错。
维护完成后,在原会话执行:
UNLOCK TABLES;
锁才会释放。
---
避坑指南:新手最容易踩的五个坑
坑一:用read_only却用root去写数据。
read_only对SUPER无效,root写入不会报错,但会破坏维护窗口的数据静止状态。
维护期间只用普通账号做验证,不要用root改业务数据。
坑二:FTWRL执行后退出会话。
锁会随连接断开自动释放,你以为锁着,实际上站点已经能写了。
保持会话连接,或者用nohup挂后台。
坑三:忘记检查从库状态。
如果站点有主从架构,主库锁写后从库可能还在应用旧的中继日志。
建议先确认从库SHOW SLAVE STATUS中Seconds_Behind_Master为0,再锁主库。
坑四:锁写期间执行DDL。
read_only模式下DDL会被拒绝,FTWRL模式下DDL会等待锁释放。
维护窗口内不要做表结构变更,否则容易卡死。
坑五:没有设置超时导致连接堆积。
锁写后应用层写入请求会报错或等待,建议提前在应用侧关闭写入入口,或者设置wait_timeout避免连接占满。
---
效果验证与恢复检查
维护完成后,按下面清单逐项确认:
- 执行
SET GLOBAL read_only = OFF;或UNLOCK TABLES; - 用普通账号执行一条INSERT,确认不再报1290错误
- 检查应用日志,确认写入请求恢复正常
- 如果有主从,检查从库延迟是否归零
- 观察
SHOW PROCESSLIST,确认没有大量等待锁的线程
可独立摘录的判断句:read_only适合保留管理操作的维护场景,FTWRL适合需要绝对静止的备份迁移场景;
FTWRL的锁在会话断开时自动释放,必须保持连接直到维护结束。
---
常见疑问
read_only和FTWRL能同时用吗?
可以,但没必要。FTWRL已经阻止所有写入,再设read_only不会增加额外效果。
锁写期间站点报错怎么办?
这是预期行为。建议提前在Nginx或应用层返回维护页面,而不是让用户看到数据库报错。
锁写会影响读操作吗?
read_only不影响读,FTWRL也不阻止SELECT,但会阻塞DDL和写入。读操作正常执行。
忘记解锁怎么办?
read_only可以重新登录执行SET GLOBAL read_only = OFF;。FTWRL如果会话已断开,锁已自动释放,不需要额外操作。
---
维护窗口锁写是数据库运维的基本功,核心就是选对锁类型、保持会话、验证生效、及时解锁。
建议先在测试环境走一遍流程,确认应用侧能正确处理写入报错,再上生产环境操作。