部分使用MySQL的数据库维护人员或者软件开发人员可能已经知道MySQL存在2038年问题,网络上有很多解决思路,但是很大一部分都是错误的,实际解决不了问题。针对于此,个人基于实际模拟的2038年MySQL问题,以及针对性解决后的测试验证,真实还原MySQL的2038年问题解决过程。
一、背景
MySQL的2038年问题源于其早期版本中TIMESTAMP类型的时间存储机制。该类型使用32位有符号整数表示自1970年1月1日(UTC)以来的秒数,最大值限制为2^31-1(即2038年1月19日03:14:07,对应北京时间是2038年1月19日11:14:07)。超过此时间后,时间戳将回滚至1970年1月1日,导致数据库时间计算错误。这一问题最直观的影响是MySQL服务会自动停止运行,对所有依赖MySQL数据库的系统影响深远。最简单的验证方法是在运行MySQL服务的环境中,手动更改系统时间超过2038年1月19日,会发现MySQL服务瞬时停止。
二、解决思路
解决MySQL 2038年问题的办法只有一个,那就是升级MySQL版本。
MySQL在8.0.28版本解决了2038年问题,其官方在该版本的改动说明中进行了描述:
The functions FROM_UNIXTIME(), UNIX_TIMESTAMP(), and CONVERT_TZ() now handle 64-bit values on platforms that support them, including 64-bit versions of Linux, MacOS, and Windows.
On compatible platforms, FROM_UNIXTIME() now accepts a maximum argument of 32536771199.999999 seconds, corresponding to '3001-01-18 23:59:59.999999' UTC (including the optional fraction of up to 6 digits). If the argument is larger than this, the function returns NULL.
On compatible platforms, UNIX_TIMESTAMP() now accepts a maximum value of '3001-01-18 23:59:59.999999' UTC, corresponding to 32536771199.999999 seconds since the Unix Epoch. If the argument is larger than this, the function returns 0.
In addition, on compatible platforms, CONVERT_TZ() now performs time zone conversion beyond 2038, up to '3001-01-18 23:59:59.999999' UTC. If the datetime argument exceeds this value, the argument is returned unchanged. This “no-op” behavior is the same as previously with values beyond '2038-01-19 03:14:07.999999' UTC.
The behavior of these 3 functions on 32-bit platforms is unchanged.
The behavior of the TIMESTAMP type is also unaffected by this change; its maximum allowed value remains '2038-01-19 03:14:07.999999' UTC, regardless of platform. For dates futureward of this, use the MySQL DATETIME type instead. (WL #14630)
三、具体操作
截止今天,MySQL官网可以下载的稳定高版本有8.0.42和8.4.5两个版本。其中,8.4.5是LTS版本(Long Term Support,长期支持),相对技术支持有保障一些。
大家可以根据需要下载配套平台的安装包进行安装更新,也可以下载源码包进行自定义编译安装。在基于源码包进行编译时,需要考虑平台的GCC版本是否满足需求,特别是一些嵌入式平台,实际平台环境可能是较久时间之前打造的,对应的GCC版本相对较老,可能没有新版本GCC。
通过查看MySQL源码包中的“cmake/os/Linux.cmake”文件,可以知道该版本MySQL源码编译所需的GCC版本号。具体可以打开该文件并搜索“GCC”字样,可以看到类似信息:
# We require at least GCC 7.1 Clang 5
IF(NOT FORCE_UNSUPPORTED_COMPILER)
IF(MY_COMPILER_IS_GNU)
IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.1)
MESSAGE(FATAL_ERROR "GCC 7.1 or newer is required")
ENDIF()
ELSEIF(MY_COMPILER_IS_CLANG)
IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
MESSAGE(FATAL_ERROR "Clang 5 or newer is required!")
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "Unsupported compiler!")
ENDIF()
ENDIF()
通过该方法,我们知道编译8.0.42版本MySQL所需的GCC最低版本为7.1,而编译8.4.5版本MySQL所需的GCC最低版本为10。
四、总结
通过升级MySQL到当前最新版本(实际不一定需要最新版本,但是确保不低于8.0.28版本),然后再调整系统时间超过2038年1月19日,会发现MySQL服务依然正常运行,对应信息系统也是正常运行,可确认MySQL的2038年问题已彻底解决。对于需要长期稳定运行和维护的系统,建议提前考虑对应的问题解决,避免到点前再处理而导致措手不及。
五、联系
如果您在操作中遇到疑问或有其他想法,欢迎联系我,我会尽快回复并提供帮助!