| 版本 | 限制 | 文檔說明 |
| 5.5 | 每表最多一個 TIMESTAMP 欄位可用 CURRENT_TIMESTAMP | 無法同時用於 DEFAULT 與 ON UPDATE 的不同欄位 |
| 5.6.5+ | 無限制 | 任何 TIMESTAMP/DATETIME 欄位可任意組合 DEFAULT/ON UPDATE CURRENT_TIMESTAMP |
方案一:升級 MySQL 版本 (根治)
升級至 5.6.5+ 或 8.0,直接支援多欄位自動時間戳,無需代碼修改。
方案二:使用 DATETIME + 觸發器 (5.5 相容)
將自動更新欄位改為 DATETIME,配合 BEFORE UPDATE 觸發器維護:
CREATE TABLE `example` (
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`lastUpdated` DATETIME NOT NULL, -- 改為 DATETIME
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
DROP TRIGGER IF EXISTS `update_example_trigger`;
DELIMITER //
CREATE TRIGGER `update_example_trigger` BEFORE UPDATE ON `example`
FOR EACH ROW
BEGIN
SET NEW.`lastUpdated` = NOW();
END//
DELIMITER ;
優點: 5.5 完美相容、語義清晰
缺點: 觸發器增加寫入開銷、維護成本、NOW() 精度為秒
方案三:應用層維護 (完全可控)
在應用代碼 (PHP/Java/Go/Python) 明確設定兩個欄位值:
-- 插入時
INSERT INTO example (created, lastUpdated) VALUES (NOW(), NOW());
-- 更新時
UPDATE example SET lastUpdated = NOW() WHERE id = ?;
優點: 版本無關、業務邏輯集中、可用高精度時間 (如 NOW(6) 微秒)
缺點: 依賴應用層規範、易漏寫、分布式系統需統一時間源
方案四:單一 TIMESTAMP + 計算欄位 (5.7+ 虛擬欄位)
CREATE TABLE `example` (
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- 5.7+ 虛擬欄位 (不佔儲存)
`lastUpdated` DATETIME GENERATED ALWAYS AS (`updated`) VIRTUAL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
最佳實踐建議
- 新專案:直接使用 MySQL 8.0,原生支援多
DATETIME/TIMESTAMP 自動時間戳
- 維護 5.5 舊系統:採用方案二 (觸發器) 或方案三 (應用層),統一團隊規範
- 遷移評估:
mysql_upgrade 後檢查 SHOW CREATE TABLE 確認欄位定義自動展開
- 時間精度:5.6.4+ 支援
TIMESTAMP(6)/DATETIME(6) 微秒精度,建議新表統一使用
驗證腳本
-- 檢查表中所有自動時間戳欄位
SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'your_db'
AND (EXTRA LIKE '%DEFAULT_GENERATED%' OR EXTRA LIKE '%ON UPDATE%')
AND DATA_TYPE IN ('timestamp','datetime');
- 上一篇文章: Debian/Ubuntu 徹底卸載 MySQL/MariaDB 並清理殘留文件指南
- 下一篇文章: MySQL GROUP BY 與 ORDER BY 執行順序深度解析:取每組最新記錄的正確姿勢
Copyright ©
程式碼之家 All Rights Reserved