目录
时间戳数据存取
时间戳字段定义
时间戳类型引发的异常
时间戳类型和时间类型选择
时间戳类型使用建议
Timestamp和datetime的异同
设置timestamp和date的自动更新时间
2038问题
解决方案
首页 数据库 mysql教程 Mysql的timestamp时间戳2038问题怎么解决

Mysql的timestamp时间戳2038问题怎么解决

Jun 02, 2023 am 10:13 AM
mysql timestamp

时间戳是指格林威治时间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’ 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_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_TIMESTAMP;

当建表语句中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’;

PS1: MySQL 5.6版本和MySQL 5.7版本中主要差异受参数explicit_defaults_for_timestamp的默认值影响。

PS2:当时间戳列的默认值为’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是有上限的,超过了,自然会报错。 部分截图如下:

Mysql的timestamp时间戳2038问题怎么解决

解决方案

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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

mysql用户和数据库的关系 mysql用户和数据库的关系 Apr 08, 2025 pm 07:15 PM

MySQL 数据库中,用户和数据库的关系通过权限和表定义。用户拥有用户名和密码,用于访问数据库。权限通过 GRANT 命令授予,而表由 CREATE TABLE 命令创建。要建立用户和数据库之间的关系,需创建数据库、创建用户,然后授予权限。

MySQL:初学者的数据管理易用性 MySQL:初学者的数据管理易用性 Apr 09, 2025 am 12:07 AM

MySQL适合初学者使用,因为它安装简单、功能强大且易于管理数据。1.安装和配置简单,适用于多种操作系统。2.支持基本操作如创建数据库和表、插入、查询、更新和删除数据。3.提供高级功能如JOIN操作和子查询。4.可以通过索引、查询优化和分表分区来提升性能。5.支持备份、恢复和安全措施,确保数据的安全和一致性。

mysql用户名和密码怎么填 mysql用户名和密码怎么填 Apr 08, 2025 pm 07:09 PM

要填写 MySQL 用户名和密码,请:1. 确定用户名和密码;2. 连接到数据库;3. 使用用户名和密码执行查询和命令。

MySQL 中的查询优化对于提高数据库性能至关重要,尤其是在处理大型数据集时 MySQL 中的查询优化对于提高数据库性能至关重要,尤其是在处理大型数据集时 Apr 08, 2025 pm 07:12 PM

1.使用正确的索引索引通过减少扫描的数据量来加速数据检索select*fromemployeeswherelast_name='smith';如果多次查询表的某一列,则为该列创建索引如果您或您的应用根据条件需要来自多个列的数据,则创建复合索引2.避免选择*仅选择那些需要的列,如果您选择所有不需要的列,这只会消耗更多的服务器内存并导致服务器在高负载或频率时间下变慢例如,您的表包含诸如created_at和updated_at以及时间戳之类的列,然后避免选择*,因为它们在正常情况下不需要低效查询se

忘记数据库密码,能在Navicat中找回吗? 忘记数据库密码,能在Navicat中找回吗? Apr 08, 2025 pm 09:51 PM

Navicat本身不存储数据库密码,只能找回加密后的密码。解决办法:1. 检查密码管理器;2. 检查Navicat的“记住密码”功能;3. 重置数据库密码;4. 联系数据库管理员。

mysql怎么查看 mysql怎么查看 Apr 08, 2025 pm 07:21 PM

通过以下命令查看 MySQL 数据库:连接到服务器:mysql -u 用户名 -p 密码运行 SHOW DATABASES; 命令获取所有现有数据库选择数据库:USE 数据库名;查看表:SHOW TABLES;查看表结构:DESCRIBE 表名;查看数据:SELECT * FROM 表名;

navicat premium怎么创建 navicat premium怎么创建 Apr 09, 2025 am 07:09 AM

使用 Navicat Premium 创建数据库:连接到数据库服务器并输入连接参数。右键单击服务器并选择“创建数据库”。输入新数据库的名称和指定字符集和排序规则。连接到新数据库并在“对象浏览器”中创建表。右键单击表并选择“插入数据”来插入数据。

mysql怎么复制表 mysql怎么复制表 Apr 08, 2025 pm 07:24 PM

在 MySQL 中复制表需要创建新表、插入数据、设置外键、复制索引、触发器、存储过程和函数。具体步骤包括:创建具有相同结构的新表。将数据从原始表插入新表。设置相同的外键约束(如果原始表有)。创建相同索引。创建相同触发器(如果原始表有)。创建相同存储过程或函数(如果原始表使用了)。

See all articles