trx_id为0或缺失不是bug,而是mysql 8.0+对显式start transaction read only事务主动跳过分配的结果,因其无需参与mvcc可见性判断;begin、set transaction read only或autocommit=1下的单条select均不触发该优化,混入任何写操作或锁读即终止只读状态。

TRX_ID 为 0 或缺失,不是 bug,也不是配置异常——这是 MySQL 8.0+ 对真正只读事务的主动跳过行为,核心原因是:它根本不需要参与 MVCC 可见性判断。
只有 START TRANSACTION READ ONLY 才触发跳过逻辑
显式声明是硬门槛。以下写法**都不算**只读事务优化:
-
BEGIN后跟SELECT:仍分配TRX_ID、创建read view、注册到活跃事务链表 -
SET TRANSACTION READ ONLY:仅影响后续事务,对已BEGIN的当前事务无效 -
autocommit=1下单条SELECT:归类为AC-NL-RO-SELECT,TRX_ID显示为 0,但不复用全局只读 ID,也不省略 read view 创建
TRX_ID 缺失在监控中怎么识别
别靠 SHOW ENGINE INNODB STATUS 直接找 TRX_ID 字段——它对只读事务会省略或填占位值(如 4294967295)。更可靠的方式是查:
-
INFORMATION_SCHEMA.INNODB_TRX表,过滤条件:TRX_ISOLATION_LEVEL = 'REPEATABLE READ' AND TRX_ROWS_LOCKED = 0 - 若
TRX_ID字段为NULL或空字符串,基本可确认未分配 -
TRX_STATE = 'RUNNING'且TRX_ROWS_MODIFIED = 0是辅助佐证
混入任何写操作都会立刻“降级”
只读事务极其脆弱,一个看似无害的操作就能让它失效:
-
SELECT ... FOR UPDATE或LOCK IN SHARE MODE:直接转为读写模式,立即分配TRX_ID -
INSERT INTO ... SELECT、SELECT ... INTO OUTFILE:Server 层报错ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION (1792),事务终止 -
CREATE TEMPORARY TABLE+INSERT:允许,但此时会为该事务分配TRX_ID(因涉及临时表变更)
真正容易被忽略的是:事务是否只读,取决于**执行路径中的实际语句**,而非开头声明——哪怕写了 READ ONLY,只要中间执行了一条带锁读或隐式写,优化就作废。











