古詩詞大全網 - 字典詞典 - 技術分享 | MySQL:壹文弄懂時區&time_zone

技術分享 | MySQL:壹文弄懂時區&time_zone

妳還在被以下問題困擾嗎:

MySQL 的安裝規範中應該設置什麽時區?

JAVA 應用讀取到的時間和北京時間差了14個小時,為什麽?怎麽解決?

已經運行壹段時間的業務,修改 MySQL 的時區會影響已經存儲的時間類型數據嗎?

遷移數據時會有導致時間類型數據時區錯誤的可能嗎?

...

看完這篇文章,妳能解決上面所有的疑惑。首先出場的是和時區相關的啟動參數和系統變量。

如果要在 MySQL 啟動時就指定時區,則應該使用啟動參數: default-time-zone ,示例:

啟動後我們可以看到控制時區的系統變量,其中 time_zone 變量控制時區,在MySQL運行時可以通過 set 命令修改(註意:不可以寫在 my.cnf 中):

啟動參數和系統變量的可用值遵循相同的格式:

system_time_zone 變量只有全局值沒有會話值,不能動態修改,MySQL 啟動時,將嘗試自動確定服務器的時區,並使用它來設置 system_time_zone 系統變量, 此後該值不變。當 time_zone='system' 時,就是使用的這個時區,示例中 time_zone 就是 CST,而 CST 在 RedHat 上就是東八區:

概括壹下就兩點:

1. NOW() 和 CURTIME() 系統函數的返回值受當前 session 的時區影響

不僅是select now(),包括insert .. values(now())、以及字段的 DEFAULT CURRENT_TIMESTAMP 屬性也受此影響:

2. timestamp 數據類型字段存儲的數據受時區影響

timestamp 數據類型會存儲當時session的時區信息,讀取時會根據當前 session 的時區進行轉換;而 datetime 數據類型插入的是什麽值,再讀取就是什麽值,不受時區影響。也可以理解為已經存儲的數據是不會變的,只是 timestamp 類型數據在讀取時會根據時區轉換:

關於時區所有明面上的東西都在上面了,我們前面提到的困擾就是在暗處的經驗。

1. MySQL的安裝規範中應該設置什麽時區?

對於國內的業務了,在 my.cnf 寫入 default-time-zone='+08:00' `,其他地區和開發確認取對應時區即可。

為什麽不設置為 system 呢?使用系統時間看起來也是個不錯的選擇,比較省事。不建議的原因有兩點:

2. JAVA應用讀取到的時間和北京時間差了14個小時,為什麽?怎麽解決?

這通常是 JDBC 參數中沒有為連接設置時區屬性(用 serverTimezone 參數指定),並且MySQL中沒有設置全局時區,這樣MySQL默認使用的是系統時區,即 CST。這樣壹來應用與MySQL 建立的連接的 session time_zone 為 CST ,前面我們提到 CST 在 RedHat 上是 +08:00 時區,但其實它壹***能代表4個時區:

JDBC在解析CST時使用了美國標準時間,這就會導致時區錯誤。要解決也簡單:壹是遵守上面剛說到的規範,對MySQL顯示的設置'+08:00'時區;二是JDBC設置正確的 serverTimezone。

3. 已經運行壹段時間的業務,修改MySQL的時區會影響已經存儲的時間類型數據嗎?

完全不會,只會影響對 timestamp 數據類型的讀取。這裏不得不提壹句,為啥要用 timestamp?用 datetime 不香嗎,範圍更大,存儲空間其實差別很小,趕緊加到開發規範中吧。

4. 遷移數據時會有導致時間類型數據時區錯誤的可能嗎?

這個還真有,還是針對 timestamp 數據類型,比如使用 mysqldump 導出 csv 格式的數據,默認這種導出方式會使用 UTC 時區讀取 timestamp 類型數據,這意味導入時必須手工設置 session.time_zone='+00:00'才能保證時間準確:

如何避免?mysqldump 也提供了壹個參數 --skip-tz-utc ,意思就是導出數據的那個連接不設置 UTC 時區,使用 MySQL 的 gloobal time_zone 系統變量值。

其實 mysqldump 導出 sql 文件時默認也是使用 UTC 時區,並且會在導出的 sql 文件頭部帶有 session time_zone 信息,這樣可以保證導 SQL 文件導入和導出時使用相同的時區,從而保證數據的時區正確(而導出的 csv 文件顯然不可以攜帶此信息)。需要註意的是 --compact 參數會去掉 sql 文件的所有頭信息,所以壹定要記得: --compact 參數得和 --skip-tz-utc 壹起使用。