詳解MySQL中timestamp和datetime時(shí)區(qū)問題導(dǎo)致做DTS遇到的坑
MySQL中如何表示當(dāng)前時(shí)間?
其實(shí),表達(dá)方式還是蠻多的,匯總?cè)缦拢?/p>
Data Type | “Zero” Value |
---|---|
DATE |
'0000-00-00' |
TIME |
'00:00:00' |
DATETIME |
'0000-00-00 00:00:00' |
TIMESTAMP |
'0000-00-00 00:00:00' |
YEAR |
0000 |
datetime和timestamp這兩種類型都是用于表示YYYY-MM-DD HH:MM:SS 這種年月日時(shí)分秒格式的數(shù)據(jù),但兩者還是有些許不同之處的。
結(jié)論
- timestamp實(shí)際存儲(chǔ)的是1970-01-01 00:00:00 UTC到目前的秒數(shù)占4字節(jié)(時(shí)間精度為毫秒和納秒時(shí)會(huì)占用更多字節(jié)),故相當(dāng)于是帶時(shí)區(qū)的時(shí)間,通過設(shè)置會(huì)話的時(shí)區(qū),會(huì)自動(dòng)轉(zhuǎn)換為設(shè)置的時(shí)區(qū)的時(shí)間
- datetime存儲(chǔ)的就是格式化后的字符串類似'2021-12-05 13:27:53.957033',不攜帶時(shí)區(qū)信息,在UTC和CST時(shí)區(qū)查詢到的結(jié)果是一致的,例如在CST時(shí)區(qū)寫入的'2021-12-05 13:27:53.957033',但是在UTC時(shí)區(qū)查詢到的還是'2021-12-05 13:27:53.957033',如果沒做時(shí)區(qū)轉(zhuǎn)換,就相當(dāng)于是直接將CST時(shí)間映射為UTC時(shí)間,但是實(shí)際上UTC時(shí)間比CST時(shí)間慢8個(gè)小時(shí)
驗(yàn)證
環(huán)境準(zhǔn)備,簡(jiǎn)而言之就是存在一張表有timestamp字段和datetime字段,且當(dāng)前服務(wù)端為CST時(shí)區(qū)
mysql> show create table test_time\G; *************************** 1. row *************************** Table: test_time Create Table: CREATE TABLE `test_time` ( `id` int NOT NULL AUTO_INCREMENT, `ts` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `dt` datetime(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> show variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | SYSTEM | +------------------+--------+ 2 rows in set (0.01 sec)
插入一條數(shù)據(jù),當(dāng)前CST時(shí)區(qū)下ts和dt結(jié)果相同
mysql> select * from test_time; Empty set (0.00 sec) mysql> insert into test_time() values(); Query OK, 1 row affected (0.00 sec) mysql> select * from test_time; +----+----------------------------+----------------------------+ | id | ts | dt | +----+----------------------------+----------------------------+ | 3 | 2021-12-05 15:04:13.293949 | 2021-12-05 15:04:13.293949 | +----+----------------------------+----------------------------+ 1 row in set (0.00 sec)
將會(huì)話的時(shí)區(qū)設(shè)置為UTC時(shí)區(qū)再次查詢,ts由于從CST時(shí)區(qū)變?yōu)閁TC時(shí)區(qū)查詢到的結(jié)果比之前慢8個(gè)小時(shí),由于dt不帶時(shí)區(qū)信息,結(jié)果不變
mysql> set time_zone='+00:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from test_time; +----+----------------------------+----------------------------+ | id | ts | dt | +----+----------------------------+----------------------------+ | 3 | 2021-12-05 07:04:13.293949 | 2021-12-05 15:04:13.293949 | +----+----------------------------+----------------------------+ 1 row in set (0.01 sec)
從剛剛insert產(chǎn)生的binlog中也有體現(xiàn),ts在binlog中存儲(chǔ)為時(shí)間戳(從1970-01-01 00:00:00 UTC到目前的秒數(shù))相當(dāng)于帶UTC時(shí)區(qū)信息,dt為不帶時(shí)區(qū)信息,結(jié)果為格式化后的字符串2021-12-05 15:04:13.293949,主要關(guān)注倒數(shù)第4第5行,@2=1638687853.293949表示ts字段的值, @3='2021-12-05 15:04:13.293949'表示dt字段的值
[mysql %] mysqlbinlog -v --base64-output=decode-rows ./mysqlbin.000012 ... ... SET @@SESSION.GTID_NEXT= '1cf4493a-dafd-11eb-944c-4016af29c14c:1416767'/*!*/; # at 14220 #211205 15:04:13 server id 1 end_log_pos 14308 CRC32 0x1fd913a3 Query thread_id=137 exec_time=0 error_code=0 SET TIMESTAMP=1638687853.293949/*!*/; BEGIN /*!*/; # at 14308 #211205 15:04:13 server id 1 end_log_pos 14368 CRC32 0xbb8937fb Table_map: `testa`.`test_time` mapped to number 121 # at 14368 #211205 15:04:13 server id 1 end_log_pos 14423 CRC32 0x2e0a3baa Write_rows: table id 121 flags: STMT_END_F ### INSERT INTO `testa`.`test_time` ### SET ### @1=3 ### @2=1638687853.293949 ### @3='2021-12-05 15:04:13.293949' # at 14423 #211205 15:04:13 server id 1 end_log_pos 14454 CRC32 0x68cee280 Xid = 1416 COMMIT/*!*/;
坑
- 如果在做DTS相關(guān)項(xiàng)目時(shí),使用解析MySQL binlog的開源工具,例如github.com/go-mysql-org/go-mysql,如果配置了parseTime=true會(huì)將timestamp類型字段解析為L(zhǎng)ocal時(shí)間,將datetime類型解析為UTC時(shí)間,也可配置為false獲取到的就是字符串(timestamp已轉(zhuǎn)換為會(huì)話時(shí)區(qū)的時(shí)間,datetime就是binlog中原生的字符串)自己解析,如果parseTime=true且不是使用的UTC時(shí)間插入的datetime字段,理論上拿到的時(shí)間已經(jīng)不正確了,相當(dāng)于直接將CST的2021-12-05 15:04:13.293949轉(zhuǎn)換為了UTC的2021-12-05 15:04:13.293949,實(shí)際上應(yīng)該轉(zhuǎn)換為UTC的2021-12-05 07:04:13.293949才正確
- 如果剛好業(yè)務(wù)需求中有time.Now()獲取的Local時(shí)間和datetime類型字段比較的場(chǎng)景,需要注意時(shí)區(qū)問題,或者將時(shí)間都去掉時(shí)區(qū),轉(zhuǎn)換為格式化后的字符串相比較
- 由于datetime本身就不帶時(shí)區(qū)信息,除了轉(zhuǎn)換UTC時(shí)間,也沒有更好的選擇,所以很坑!
到此這篇關(guān)于詳解MySQL中timestamp和datetime時(shí)區(qū)問題導(dǎo)致做DTS遇到的坑的文章就介紹到這了,更多相關(guān)MySQL timestamp和datetime坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL的InnoDB擴(kuò)容及ibdata1文件瘦身方案完全解析
在使用InnoDB存儲(chǔ)引擎后,MySQL的ibdata1文件常常會(huì)占據(jù)大量存儲(chǔ)空間,這里我們就為大家?guī)鞰ySQL的InnoDB擴(kuò)容及ibdata1文件瘦身方案完全解析:2016-06-06mysql group by having 實(shí)例代碼
mysql中g(shù)roup by語句用于分組查詢,可以根據(jù)給定數(shù)據(jù)列的每個(gè)成員對(duì)查詢結(jié)果進(jìn)行分組統(tǒng)計(jì),最終得到一個(gè)分組匯總表, 經(jīng)常和having一起使用,需要的朋友可以參考下2016-11-11mysql 報(bào)錯(cuò)This function has none of DETERMINISTIC解決方案
這篇文章主要介紹了mysql 報(bào)錯(cuò)This function has none of DETERMINISTIC解決方案的相關(guān)資料,需要的朋友可以參考下2016-11-11Navicat連接MySQL時(shí)報(bào)10060、1045錯(cuò)誤及my.ini位置問題
這篇文章主要介紹了Navicat連接MySQL的10060及1045報(bào)錯(cuò),my.ini位置,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03MySQ索引操作命令總結(jié)(創(chuàng)建、重建、查詢和刪除索引命令詳解)
本篇文章主要是對(duì)MySQL索引操作方法做了一下總結(jié),包括創(chuàng)建索引、重建索引、查詢索引、刪除索引的操作2014-04-04