<p>MySQL 8.0.23+ 中 ALTER TABLE MODIFY COLUMN 不支持设 INVISIBLE,报错 ERROR 3105;正确语法是 ALTER TABLE ... ALTER COLUMN col SET INVISIBLE 或 CHANGE COLUMN col col type INVISIBLE;INVISIBLE 仅影响 SELECT * 默认行为,不提供写保护,非权限机制。</p>

ALTER TABLE MODIFY COLUMN 不能直接设 INVISIBLE?
不是语法不支持,而是 MODIFY COLUMN 默认保留原列可见性 —— 它不会自动继承 INVISIBLE 属性。如果你执行:ALTER TABLE t1 MODIFY COLUMN age INT INVISIBLE;,MySQL 会报错 ERROR 3105 (HY000): The 'INVISIBLE' attribute is not supported for this operation。
真正能生效的写法只有两种:
-
ALTER TABLE t1 ALTER COLUMN age SET INVISIBLE;(推荐,语义清晰) -
ALTER TABLE t1 CHANGE COLUMN age age INT INVISIBLE;(需重复列名,易漏写)
注意:SET INVISIBLE 是 MySQL 8.0.23+ 才支持的语法;低于该版本只能用 CHANGE COLUMN 替代,且必须显式写出完整定义(类型、默认值等),否则会丢失原有属性。
INSERT 不写列名时,Invisible Column 怎么填值?
它按默认行为处理:有 DEFAULT 就用默认值,是 NOT NULL 但没默认值就报错,NULL 列则填 NULL。
比如这张表:CREATE TABLE users (id INT, name VARCHAR(50), version INT DEFAULT 1 INVISIBLE);
下面这条语句完全合法:INSERT INTO users VALUES (1, 'Alice');
结果中 version 自动为 1。
但这条会失败:CREATE TABLE logs (msg TEXT, ts TIMESTAMP INVISIBLE);INSERT INTO logs VALUES ('error');
因为 ts 是 NOT NULL 且无默认值,MySQL 拒绝隐式忽略它。
SELECT * 真的看不见 Invisible Column 吗?
是的,但仅限于字面意义上的 SELECT *。只要 SQL 中出现任何显式列引用,哪怕只是 SELECT 1 或 SELECT * FROM (SELECT *) AS t,都可能触发元数据重解析,导致部分客户端(如旧版 Connector/J)意外暴露列。
更稳妥的验证方式是查系统表:SELECT COLUMN_NAME, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND EXTRA = 'INVISIBLE';
注意:EXTRA 字段值是字符串 'INVISIBLE',不是布尔值;且某些 ORM(如 SQLAlchemy 1.4)在反射表结构时默认跳过 EXTRA = 'INVISIBLE' 的列,但 2.0+ 版本已修复此行为。
为什么 DESCRIBE 显示 INVISIBLE 却 SELECT * 还是返回该列?
大概率是你用的客户端缓存了表结构,或者服务端用了查询缓存(已弃用但某些配置仍残留)。DESCRIBE 和 SHOW CREATE TABLE 都会如实显示 INVISIBLE 标记,但最终是否隐藏,取决于执行时优化器对当前 SQL 的解析逻辑。
最直接的排查步骤:
- 确认 MySQL 版本 ≥ 8.0.23(
SELECT VERSION();) - 执行
FLUSH TABLES;清掉表定义缓存 - 新开一个连接重试
SELECT * FROM t1;
如果仍有异常,检查是否启用了 sql_mode 中的 IGNORE_SPACE 或自定义 parser 插件 —— 极少数第三方中间件会绕过 invisible 列的过滤逻辑。
Invisible Column 的“不可见”是 SQL 层的轻量级开关,不是权限或加密机制;它依赖优化器严格遵循语法解析路径,任何绕过标准 parser 的调用(如预编译语句绑定参数时未声明列、使用 LOAD DATA INFILE 且未指定字段列表)都可能让这个特性失效。


















