Navicat默认开启autocommit=1,UPDATE/DELETE立即生效且不可回滚;必须手动执行SET AUTOCOMMIT = 0和SET SQL_SAFE_UPDATES = 1,并以右下角“Transaction”标识及SELECT @@autocommit返回0为准。

Navicat 默认不开启事务,UPDATE 一执行就永久生效
Navicat 连接 MySQL 时默认发送 SET AUTOCOMMIT = 0(注意:这是错的——实际是 SET AUTOCOMMIT = 1),也就是说每条 UPDATE、DELETE 都自动提交,没有回滚机会。它不像 psql 或 DBeaver 那样在执行前弹窗提示“此操作将影响 X 行,是否继续?”,也不像某些 IDE 那样默认包裹在事务里。你看到“Affected rows: 12345”只是执行结果反馈,不是安全确认。
为什么图形界面的「Use transaction」勾选项不可靠
这个选项只对当前查询编辑器标签页有效,且仅作用于**该次执行的 SQL 块**(比如你粘贴了多条语句,它只对第一条起作用);关闭标签页、切换连接、甚至 Ctrl+Enter 多次执行后,状态就重置。更关键的是:它不改变会话级 AUTOCOMMIT 值,底层仍是 autocommit=1,所以一旦执行中断(如网络抖动、Navicat 卡死),部分语句已提交,部分未执行,形成数据不一致。
- 验证方式:执行
SELECT @@autocommit;—— 返回1即为危险状态 - 右下角状态栏显示 ✓ 时,代表 autocommit on;∅ 才是 off(但默认不是 ∅)
- 勾选了「Use transaction」却仍没回滚能力?大概率是因为你执行的是单条语句,而 Navicat 的事务包装逻辑只对多语句块生效
真正有效的防护必须靠手动 SQL 控制
别依赖界面开关,每次连上生产库第一件事就是运行这两行:
SET SQL_SAFE_UPDATES = 1;<br>SET AUTOCOMMIT = 0;
前者拦截无 WHERE 或全表扫描的 UPDATE/DELETE,后者让所有后续 DML 进入暂存状态。之后流程必须严格遵循:
- 先
SELECT COUNT(*) FROM ... WHERE ...确认范围 - 再执行
UPDATE,看底部 “Affected rows” 是否符合预期 - 没问题就
COMMIT;出错立刻ROLLBACK -
SET AUTOCOMMIT = 0只对当前会话有效,断连即失效,必须重输
批量替换文本时最容易忽略的坑
用 regexp_replace() 或 replace() 做字段内容替换,看似只是 SELECT 类操作,但一旦写进 UPDATE 就直面风险。常见疏漏包括:
- 正则中点号没转义:
'old-site.com'会匹配old-siteXcom,应写成'old-site\.com' - 用
LIKE写WHERE条件,导致误判:WHERE bio LIKE '%old-site.com%'比WHERE bio ~ 'old-site\.com'更容易漏掉边界情况 - PostgreSQL 用户误用 MySQL 语法:PG 的
replace()不支持正则,想全局替换必须用regexp_replace(..., 'g') - 没加
WHERE子句就直接跑UPDATE users SET bio = replace(bio, ...)——SQL_SAFE_UPDATES=1会拦住,但前提是它已启用
最危险的不是不会写 SQL,而是以为 Navicat 的图形界面已经帮你兜底了。它没有撤销按钮,没有操作日志回溯,也没有跨会话事务继承——所有安全责任,最终都落在你敲下的那几行 SET 和 COMMIT 上。











