業務常需「創建時間不可變、更新時間自動刷新」的雙時間戳列。MySQL 5.5 單表僅允許一個 TIMESTAMP 列使用 DEFAULT CURRENT_TIMESTAMP 或 ON UPDATE CURRENT_TIMESTAMP,5.6+ 解除此限制。本文梳理四種方案及版本演進。
5.5 文檔:一張表最多一個 TIMESTAMP 列可自動初始化/更新。
5.6.5 變更:移除限制,任意 TIMESTAMP/DATETIME 列均可組合DEFAULT與ON UPDATE子句。
CREATE TABLE temp ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(10), created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NULL ); DELIMITER $$ CREATE TRIGGER tri_temp_updated_at BEFORE UPDATE ON temp FOR EACH ROW BEGIN SET NEW.updated_at = NOW(); END$$ DELIMITER ;
created_at 自動賦值,updated_at 需顯式傳入或為 NULL。updated_at。updated_at 會存 NULL。CREATE TABLE temp ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(10), created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); DELIMITER $$ CREATE TRIGGER tri_temp_created_at BEFORE INSERT ON temp FOR EACH ROW BEGIN IF NEW.created_at IS NULL THEN SET NEW.created_at = NOW(); END IF; END$$ DELIMITER ;
updated_at 完全自動化,插入更新皆刷新。created_at 由觸發器在 INSERT 時賦值,避免 NULL。CREATE TABLE temp ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(10), created_at TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00', updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
NO_ZERO_DATE SQL 模式下會報錯;零值語義模糊,不推薦新專案使用。CREATE TABLE temp ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(10), created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
驗證:
INSERT INTO temp(name) VALUES('robin'),('wentasy');
UPDATE temp SET name='robinwen' WHERE id=1;
-- created_at 保持創建時刻,updated_at 自動刷新
| 場景 | 推薦方案 | 備註 |
|---|---|---|
| MySQL 5.6+ / 8.0 | 方案四(原生) | 首選,無額外開銷 |
| MySQL 5.5,不可升級 | 方案二(觸發器維護 created_at) | updated_at 自動化,created_at 仅 INSERT 時賦值 |
| 需時區感知、範圍更大 | 用 DATETIME + 方案四 | TIMESTAMP 範圍 1970~2038,DATETIME 1000~9999 |
| 應用層自行管理時間 | 用 DATETIME NOT NULL,應用寫入 | 去除資料庫隱式行為,利於微服務、跨時區 |
DEFAULT CURRENT_TIMESTAMP 列若顯式插入 NULL,會存 NULL(而非當前時間),需定義 NOT NULL 或觸發器兜底。DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,易導致「創建時間隨更新變化」的誤解。MySQL 5.6+ 徹底解決雙自動時間戳痛點,升級是根治之道。受限於 5.5 時,方案二(updated_at 原生自動 + created_at 觸發器賦值) 是工程上最穩健的折中。新架構建議直接使用 DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP,並由應用層統一時區處理。