Mysql的timestamp時間戳2038問題怎麼解決
時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數。
生產環境中部署著各種版本的MySQL,包括MySQL 5.5/5.6/5.7三個大版本和N個小版本,由於MySQL在向上相容性較差,導致相同SQL在不同版本上表現各異,以下從幾個方面來詳細介紹時間戳資料類型。
時間戳資料存取
在MySQL上述三個大版本中,預設時間戳(Timestamp)類型的取值範圍為’1970-01-01 00:00:01&rsquo ; UTC 至’2038-01-19 03:14:07’ UTC,資料精確到秒級別,該取值範圍包含約22億個數值,因此在MySQL內部使用4個位元組INT類型來存放時間戳資料:
1、儲存時間戳資料時,先將本地時區時間轉換為UTC時區時間,再將UTC時區時間轉換為INT格式的毫秒值(使用UNIX_TIMESTAMP函數),然後存放到資料庫中。
2、在讀取時間戳資料時,先將INT格式的毫秒值轉換為UTC時區時間(使用FROM_UNIXTIME函數),然後再轉換為本地時區時間,最後回傳給客戶端。
在MySQL 5.6.4及之後版本,可以將時間戳類型資料最高精確微秒(百萬分之一秒),資料型別定義為timestamp(N),N取值範圍為0- 6,預設為0,如需要精確到毫秒則設定為Timestamp(3),如需要精確到微秒則設定為timestamp(6),資料精確度提高的代價是其內部儲存空間的變大,但仍未改變時間戳類型的最小和最大取值範圍。
時間戳欄位定義
時間戳欄位定義主要影響兩類操作:
插入記錄時,時間戳欄位包含DEFAULT CURRENT_TIMESTAMP,如插入記錄時未指定特定時間資料則將該時間戳欄位值設為目前時間
#更新記錄時,時間戳欄位包含ON UPDATE CURRENT_TIMESTAMP,如更新記錄時未指定具體時間資料則將該時間戳欄位值設定為目前時間
PS1:CURRENT_TIMESTAMP表示使用CURRENT_TIMESTAMP()函數來取得目前時間,類似NOW()函數
#根據上面兩類操作,時間戳列可以有四張組合定義,其意義分別為:
#當欄位定義為timestamp,表示該欄位在插入和更新時都不會自動設定為目前時間。
當欄位定義為timestamp DEFAULT CURRENT_TIMESTAMP,表示該欄位僅在插入且未指定值時被賦予目前時間,再更新時且未指定值時不做修改。
當欄位定義為timestamp ON UPDATE CURRENT_TIMESTAMP,表示該欄位在插入且未指定值時被賦值為"0000-00-00 00:00:00",在更新且未指定值時更新為目前時間。
當欄位定義為timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,表示該欄位在插入或更新時未指定值,則被賦值為目前時間。
PS1:在MySQL中執行的建表語句和最終表建立語句會存在差異,建議使用SHOW CREATE TABLE TB_XXX取得已建立表格的建表語句。
時間戳字段在MySQL各版本的使用差異
在MySQL 5.5及之前版本中,只能對一個時間戳字段定義DEFUALT CURRENT_TIMESTAMP或ON UPDATE CURRENT_TIMESTAMP ,但在MySQL 5.6和MySQL 5.7版本中取消了此限制;
在MySQL 5.6版本中參數explicit_defaults_for_timestamp預設值為1,在MySQL 5.7版本中參數explicit_defaults_for_for_timestamp值為0 ;
在MySQL 5.5和MySQL 5.7版本中timestamp型別預設為NOT NULL,在MySQL 5.6版中timestamp型別預設為NULL;
#當建表語句中定於c1 timestamp 時,
在MySQL 5.5中等價於c1 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
-
在MySQL 5.6中價於c1 timestamp NULL DEFAULT NULL;
-
在MySQL 5.7中等價於c1 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMEST
#; ##當建表語句中c1 timestamp default 0時,
- 在MySQL 5.5中等價於c1 timestamp NOT NULL DEFAULT ‘0000-00-00 00:00: 00’;
- 在MySQL 5.6中等價於c1 timestamp NULL DEFAULT ‘0000-00-00 00:00:00’;
- 在MySQL 5.7中等價於c1 timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00’;
時間戳類型引發的異常
當MySQL參數time_zone=system時,查詢timestamp欄位會呼叫系統時區做時區轉換,而由於系統時區存在全域鎖定問題,在多並發大資料量訪問時會導致線程上下文頻繁切換,CPU使用率暴漲,系統回應變慢設定假死。
時間戳類型和時間類型選擇
在部分"資料庫指導"文檔中,會推薦使用timestamp類型代替datetime字段,其理由是timestamp類型使用4字節,而datetime字段使用8字節,但隨著磁碟效能提升和記憶體成本降低,在實際生產環境中,使用timestamp類型並不會帶來太多效能提升,反而可能因timestamp類型的定義和取值範圍限制和影響業務使用。
在MySQL 5.6.4及之後版本,可以將時間戳類型(timestamp)資料最高精確微秒,也同樣可以將時間型別(datetime)資料最高精確微秒,時間型別(datetime)同樣可以得到timestamp型別相同的效果,如將欄位定義為dt1 DATETIME(3) NOT NULL DEFAULT NOW(3) ON UPDATE NOW(3); 時間型別(datetime)的存取範圍’1000-01-01 00: 00:00.000000’ 至‘9999-12-31 23:59:59.999999’,能更好地存放各時段的資料。
時間戳類型使用建議
在只關心資料最後更新時間的情況下,建議將時間戳記列定義為TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
#在關心創建時間和更新時間的情況下,建議將更新時間設定為時間戳字段,將創建時間定義為DAETIME 或TIMESTAMP DEFAULT ‘0000-00-00 00:00:00’,並在插入記錄時顯式指定創建時間;
建議在表中只定義單一時間戳列,並明確定義DEFAULT 和ON UPDATE屬性;
雖然在MySQL中可以對時間戳字段賦值或更新,但建議僅在必要的情況下對時間戳列進行明確插入和更新;
建議將time_zone參數設定為system外的值,如中國地區伺服器設定為’ 8:00’;
建議將MySQL線下測試版本和線上生產版本保持一致。
Timestamp和datetime的異同
相同點:
可自動更新和初始化,預設顯示格式相同YYYY-MM-dd HH:mm :ss
不同點:
timestamp的時間範圍是:‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC ,自動時區轉化,實際儲存毫秒數,4位元組儲存
datetime的時間範圍:‘1000-01 -01 00:00:00’ to ‘9999-12-31 23:59:59’ ,不支援時區,8位元組儲存
#設定timestamp和date的自動更新時間
當對某一資料進行更新作業或插入一條新的資料而沒有為date和mydate賦值,date和mydate這兩個欄位會自動預設為目前時間
CREATE TABLE `mytime` ( `id` int(11) NOT NULL AUTO_INCREMENT, `date` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `mydate` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
2038問題
當timestamp 儲存的時間大於'2038-01-19 03:14:07' UTC,mysql就會報錯, 因為這是mysql本身的問題,也就是說timestamp是有上限的,超過了,自然會報錯。部分截圖如下:
解決方案
timestamp 雖然有上限限制,但是它保存的是時間戳,可以不用去考慮時區的問題,如果是需要處理與時區相關的需求, 解決2038 限制的時候,建議將timestamp改為整數類型,用來保存時間戳,在程序中再進行轉換(這個方案沒有實施過,僅僅是建議,慎用!! )
若不需要考慮時區問題,直接用datatime型別取代timestamp即可,因為datatime的取值範圍大很多,可看上圖;
取代的想法:
1. 修改原來字段的名字;
ALTER TABLE `student` CHANGE `entry_date` `temp_entry_date` timestamp NOT NULL default '0000-00-00 00:00:00';
新建一個datatime類型的字段(新建一列,用來替換原來的);
ALTER TABLE `student` ADD `entry_date` DATETIME NOT NULL default '0000-00-00 00:00:00';
將原來字段列的資料拷貝到新的字段列中;
UPDATE `student` SET `entry_date` = `temp_entry_date`;
刪除原來的列;
ALTER TABLE `student` DROP `temp_entry_date`;
完整sql 如下:(需要注意,原來的timestamp的預設值,這個也需要加上)
ALTER TABLE `student` CHANGE `entry_date` `temp_entry_date` timestamp NOT NULL default '0000-00-00 00:00:00'; ALTER TABLE `student` ADD `entry_date` DATETIME NOT NULL default '0000-00-00 00:00:00'; UPDATE `student` SET `entry_date` = `temp_entry_date`; ALTER TABLE `student` DROP `temp_entry_date`;
以上是Mysql的timestamp時間戳2038問題怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undress AI Tool
免費脫衣圖片

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

TosecureMySQLeffectively,useobject-levelprivilegestolimituseraccessbasedontheirspecificneeds.Beginbyunderstandingthatobject-levelprivilegesapplytodatabases,tables,orcolumns,offeringfinercontrolthanglobalprivileges.Next,applytheprincipleofleastprivile

處理大表時,MySQL性能和可維護性面臨挑戰,需從結構設計、索引優化、分錶策略等方面入手。 1.合理設計主鍵和索引:推薦使用自增整數作為主鍵以減少頁分裂;使用覆蓋索引提升查詢效率;定期分析慢查詢日誌並刪除無效索引。 2.分區表的合理使用:按時間範圍等策略分區,提升查詢和維護效率,但需注意分區裁剪問題。 3.考慮讀寫分離和分庫分錶:讀寫分離緩解主庫壓力,分庫分錶適用於數據量極大場景,建議使用中間件並評估事務和跨庫查詢問題。前期規劃和持續優化是關鍵。

檢查MySQL服務是否運行,使用sudosystemctlstatusmysql確認並啟動;2.確保bind-address設置為0.0.0.0以允許遠程連接,並重啟服務;3.驗證3306端口是否開放,通過netstat檢查並配置防火牆規則允許該端口;4.對於“Accessdenied”錯誤,需核對用戶名、密碼和主機名,登錄MySQL後查詢mysql.user表確認權限,必要時創建或更新用戶並授權,如使用'your_user'@'%';5.若因caching_sha2_password導致認證失

MySQL支持CHECK約束以強制域完整性,自8.0.16版本起生效;1.創建表時添加約束:使用CREATETABLE定義CHECK條件,如年齡≥18、薪資>0、部門限定值;2.修改表添加約束:用ALTERTABLEADDCONSTRAINT限製字段值,如姓名非空;3.使用複雜條件:支持多列邏輯和表達式,如結束日期≥開始日期且完成狀態需有結束日期;4.刪除約束:通過ALTERTABLEDROPCONSTRAINT指定名稱刪除;5.注意事項:需MySQL8.0.16 、InnoDB或MyISAM引

DELETEremovesspecificorallrows,keepstablestructure,allowsrollbackandtriggers,anddoesnotresetauto-increment;2.TRUNCATEquicklyremovesallrows,resetsauto-increment,cannotberolledbackinmostcases,doesnotfiretriggers,andkeepstablestructure;3.DROPremovesthee

實現MySQL數據血緣追踪的核心方法包括:1.利用Binlog記錄數據變更來源,開啟並解析binlog,結合應用層上下文追溯具體業務動作;2.在ETL流程中註入血緣標籤,通過工具同步時記錄源與目標的映射關係;3.給數據加註釋和元數據標籤,在建表時說明字段來源,並接入元數據管理系統形成可視化圖譜;4.注意主鍵一致性、避免過度依賴SQL解析、版本控制數據模型變化及定期校驗血緣數據,確保血緣追踪準確可靠。

Useamany-to-manyrelationshipwithajunctiontabletolinkitemsandtagsviathreetables:items,tags,anditem_tags.2.Whenaddingtags,checkforexistingtagsinthetagstable,insertifnecessary,thencreatemappingsinitem_tagsusingtransactionsforconsistency.3.Queryitemsbyta

CheckcompatibilitywithOS,applications,andfeatures;2.Backupalldata,configs,andlogs;3.Chooseupgrademethod(packagemanager,MySQLInstaller,ormanual);4.Runpost-upgradechecksandtests;5.Resolveissueslikeauthenticationpluginsordeprecatedoptions.Alwaysbackup,t
