给三列分别设置UUID()、NOW()、RAND()作为表达式默认值,真实插入三行空值,验证它们是不是每次都重新计算。
代码CREATE TABLE default_expr ( id INT PRIMARY KEY AUTO_INCREMENT, uid VARCHAR(36) DEFAULT (UUID()), created_at DATETIME DEFAULT (NOW()), rand_val DOUBLE DEFAULT (RAND()) ); INSERT INTO default_expr () VALUES (), (), (); -- 真实什么值都不给
id uid created_at rand_val 1 7ccbd492-bb29-11f1-8186-f496139cd556 2026-09-28 18:43:48 0.7270701497113985 2 7ccbd79e-bb29-11f1-8186-f496139cd556 2026-09-28 18:43:48 0.6057668240794603 3 7ccbd8d4-bb29-11f1-8186-f496139cd556 2026-09-28 18:43:48 0.8476237019967509
三行真实拿到了三个完全不同的UUID和随机数——每一行插入时都真实重新计算了一次UUID()和RAND(),不是复用同一个"默认值常量"。created_at三行显示相同,是因为三条INSERT在同一秒内真实执行完成,NOW()本身在这个精度上确实会给出相同结果,不代表它被当成了常量缓存。
在MySQL 8.0.13之前,DEFAULT子句真实只接受字面量常量(数字、字符串),唯一的例外是DEFAULT CURRENT_TIMESTAMP这个专门为TIMESTAMP/DATETIME开的特例。8.0.13开始,只要把任意表达式真实用一对括号包起来(DEFAULT (expr)),MySQL就会把它当成一个每次插入都重新求值的表达式,而不是尝试把它解析成常量——这也是为什么本文的三个默认值都真实写成了DEFAULT (UUID())而不是DEFAULT UUID(),少了这对括号会被拒绝。这个特性真实让"插入时自动生成唯一标识"、"插入时自动打时间戳"这类逻辑不再需要依赖应用层代码或者触发器,直接在表定义里就能真实完成。
每一步都是本文上面用真实INSERT跑出来的原始结果。
DEFAULT (expr)语法(MySQL 8.0.13起支持)