不可见列不是安全机制,不能防数据泄露;它仅在select *时跳过该列,显式查询、元数据查看、insert不指定列名等所有访问方式均照常生效,且主键列和二级索引列不可设为不可见。

不可见列不是安全机制,不能防数据泄露;它只在 SELECT * 时跳过该列,其他所有访问方式(显式查询、元数据查看、INSERT 不指定列名)都照常生效。
创建或添加 INVISIBLE 列必须带默认值或允许 NULL
否则 INSERT INTO t (a,b) VALUES (1,2) 会直接失败,报错 Column 'x' cannot be null 或 Data truncated。
- 正确写法示例:
ALTER TABLE users ADD COLUMN internal_flag TINYINT DEFAULT 0 INVISIBLE; - 也支持表达式默认值:
ADD COLUMN created_at DATETIME DEFAULT (NOW()) INVISIBLE; - 禁止这样写:
ADD COLUMN token VARCHAR(64) INVISIBLE;(无默认值且非 NULL) - 验证方法:执行一条旧式插入
INSERT INTO users (id, name) VALUES (100, 'alice');,确认成功且新列自动填充
ALTER TABLE MODIFY COLUMN 不能设 INVISIBLE,得用 ALTER COLUMN ... SET INVISIBLE
MODIFY COLUMN 语法本身不支持继承或修改可见性,强行写会报错 ERROR 3105 (HY000): The 'INVISIBLE' attribute is not supported for this operation。
- MySQL ≥8.0.23 推荐写法:
ALTER TABLE users ALTER COLUMN version SET INVISIBLE; - 低版本(8.0.23 前)只能用
CHANGE COLUMN,且必须重写完整定义:ALTER TABLE users CHANGE COLUMN version version INT DEFAULT 1 INVISIBLE; - 别漏掉类型和约束——
CHANGE不保留原定义,不写就丢
主键列、唯一索引列不能设为 INVISIBLE
MySQL 强制要求至少一个可见列存在,且主键列(哪怕只是普通二级索引)一旦被设为不可见,就会触发 ERROR 3522 (HY000)。
- 错误示范:
ALTER TABLE logs MODIFY COLUMN id BIGINT PRIMARY KEY INVISIBLE;→ 报错 - 但可以给无主键表加隐藏主键:
ALTER TABLE logs ADD COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY FIRST INVISIBLE;(这是合法且常用的做法) - 检查是否违规:执行前先查
SELECT COLUMN_NAME, COLUMN_KEY, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't';
验证 INVISIBLE 是否生效,别信 DESCRIBE 或客户端显示
很多客户端(如旧版 MySQL Shell、某些 ORM)会缓存表结构,导致 DESCRIBE 显示 INVISIBLE 但 SELECT * 还返回该列——这其实是本地缓存或协议解析问题,不是服务端没生效。
- 最可靠验证方式是查系统表:
SELECT COLUMN_NAME, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND EXTRA = 'INVISIBLE'; - 再配合实际 SQL 测试:
SELECT * FROM users;看结果集是否不含该列;SELECT id, internal_flag FROM users;确认仍可读取 - 注意:
SHOW CREATE TABLE里带/*!80023 INVISIBLE */注释,但这只是 DDL 定义,不影响运行时行为
真正容易被忽略的点是:INVISIBLE 列在 INSERT ... VALUES () 中按默认值/NULL 填充,但一旦应用层用了 ORM 的批量插入或反射建模,可能因字段缺失触发校验失败——所以加之前,务必确认所有写入路径是否显式指定了列名。它不是“藏起来就完事”,而是“藏得让旧逻辑无感,新逻辑可选接入”。











