前言:

在使用MySQL的过程中,你可能会遇到时区相关问题,比如说时间显示错误、时区不是东八区、程序取得的时间和数据库存储的时间不一致等等问题。其实,这些问题都与数据库时区设置有关,本篇文章将从数据库参数入手,逐步介绍时区相关内容。

1.log_timestamps参数介绍

首先说明下log_timestamps参数并不影响时区,只是设置不同会影响某些日志记录的时间。该参数主要是控制 error log、slow log、genera log 日志文件中的显示时间,但不会影响 general log 和 slow log 写到表 (mysql.general_log, mysql.slow_log) 中的显示时间。

log_timestamps是全局参数,可动态修改,默认使用UTC时区,这样会使得日志中记录的时间比北京时间慢8个小时,导致查看日志不方便。可以修改为SYSTEM变成使用系统时区。下面简单测试下该参数的作用及修改方法:

# 查看参数值
mysql> show global variables like 'log_timestamps';
+----------------+-------+
| Variable_name | Value |
+----------------+-------+
| log_timestamps | UTC |
+----------------+-------+
1 row in set (0.00 sec) # 产生慢日志
mysql> select sleep(10),now();
+-----------+---------------------+
| sleep(10) | now() |
+-----------+---------------------+
| 0 | 2020-06-24 17:12:40 |
+-----------+---------------------+
1 row in set (10.00 sec) # 慢日志文件记录内容 发现时间是UTC时间
# Time: 2020-06-24T09:12:50.555348Z
# User@Host: root[root] @ localhost [] Id: 10
# Query_time: 10.000354 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 1
SET timestamp=1592989960;
select sleep(10),now(); # 修改参数值 再次测试
mysql> set global log_timestamps = SYSTEM;
Query OK, 0 rows affected (0.00 sec) mysql> select sleep(10),now();
+-----------+---------------------+
| sleep(10) | now() |
+-----------+---------------------+
| 0 | 2020-06-24 17:13:44 |
+-----------+---------------------+
1 row in set (10.00 sec) # 慢日志文件记录内容 时间是对的
# Time: 2020-06-24T17:13:54.514413+08:00
# User@Host: root[root] @ localhost [] Id: 10
# Query_time: 10.000214 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 1
SET timestamp=1592990024;
select sleep(10),now();

2.time_zone参数介绍

time_zone参数用来设置每个连接会话的时区,该参数分为全局和会话级别,可以动态修改。默认值为SYSTEM,此时使用的是全局参数system_time_zone的值,而system_time_zone默认继承自当前系统的时区,即默认情况下MySQL时区和系统时区相同。

时区设置主要影响时区敏感的时间值的显示和存储。包括一些函数(如now()、curtime())显示的值,以及存储在TIMESTAMP类型中的值,但不影响DATE、TIME和DATETIME列中的值,因为这些数据类型在存取时未进行时区转换,而TIMESTAMP类型存入数据库的实际是UTC的时间,查询显示时会根据具体的时区来显示不同的时间。

下面我们来测试下time_zone参数修改产生的影响:

# 查看linux系统时间及时区
[root@centos ~]# date
Sun Jun 28 14:29:10 CST 2020 # 查看MySQL当前时区、时间
mysql> show global variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec) mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2020-06-28 14:31:12 |
+---------------------+
1 row in set (0.00 sec) # 创建测试表、插入部分数据
mysql> CREATE TABLE `time_zone_test` (
-> `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
-> `dt_col` datetime DEFAULT NULL COMMENT 'datetime时间',
-> `ts_col` timestamp DEFAULT NULL COMMENT 'timestamp时间',
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='time_zone测试表';
Query OK, 0 rows affected, 1 warning (0.07 sec) mysql> insert into time_zone_test (dt_col,ts_col) values ('2020-06-01 17:30:00','2020-06-01 17:30:00'),(now(),now());
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from time_zone_test;
+----+---------------------+---------------------+
| id | dt_col | ts_col |
+----+---------------------+---------------------+
| 1 | 2020-06-01 17:30:00 | 2020-06-01 17:30:00 |
| 2 | 2020-06-28 14:34:55 | 2020-06-28 14:34:55 |
+----+---------------------+---------------------+ # 改为UTC时区 并重新连接 发现timestamp存储的时间会随时区变化
mysql> set global time_zone='+0:00';
Query OK, 0 rows affected (0.00 sec)
mysql> set time_zone='+0:00';
Query OK, 0 rows affected (0.00 sec) mysql> show global variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | +00:00 |
+------------------+--------+
2 rows in set (0.00 sec) mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2020-06-28 06:36:16 |
+---------------------+
1 row in set (0.00 sec) mysql> select * from time_zone_test;
+----+---------------------+---------------------+
| id | dt_col | ts_col |
+----+---------------------+---------------------+
| 1 | 2020-06-01 17:30:00 | 2020-06-01 09:30:00 |
| 2 | 2020-06-28 14:34:55 | 2020-06-28 06:34:55 |
+----+---------------------+---------------------+
2 rows in set (0.00 sec) # 改回东八时区,恢复正常
mysql> set global time_zone='+8:00';
Query OK, 0 rows affected (0.00 sec) mysql> set time_zone='+8:00';
Query OK, 0 rows affected (0.00 sec) mysql> show global variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | +08:00 |
+------------------+--------+
2 rows in set (0.00 sec) mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2020-06-28 14:39:14 |
+---------------------+
1 row in set (0.00 sec) mysql> select * from time_zone_test;
+----+---------------------+---------------------+
| id | dt_col | ts_col |
+----+---------------------+---------------------+
| 1 | 2020-06-01 17:30:00 | 2020-06-01 17:30:00 |
| 2 | 2020-06-28 14:34:55 | 2020-06-28 14:34:55 |
+----+---------------------+---------------------+
2 rows in set (0.00 sec)

如果需要永久生效,还需写入配置文件中。例如将时区改为东八区,则需要在配置文件[mysqld]部分增加一行:default_time_zone = '+8:00'。

3.时区常见问题及如何避免

时区设置不妥可能会产生各种问题,下面我们列举下几个常见的问题及解决方法:

3.1 MySQL内部时间不是北京时间

遇到这类问题,首先检查下系统时间及时区是否正确,然后看下MySQL的time_zone,建议将time_zone改为'+8:00'。

3.2 Java程序存取的时间与数据库中的时间相差8小时

出现此问题的原因大概率是程序时区与数据库时区不一致导致的。我们可以检查下两边的时区,如果想统一采用北京时间,则可以在jdbc连接串中增加 serverTimezone=Asia/Shanghai,并且MySQL方面也可以将time_zone改为'+8:00'。

3.3 程序时间与数据库时间相差13小时或14小时

如果说相差8小时不够让人惊讶,那相差13小时可能会让很多人摸不着头脑。出现这个问题的原因是JDBC与MySQL对 “CST” 时区协商不一致。因为CST时区是一个很混乱的时区,有四种含义:

  • 美国中部时间 Central Standard Time (USA) UTC-05:00或UTC-06:00
  • 澳大利亚中部时间 Central Standard Time (Australia) UTC+09:30
  • 中国标准时 China Standard Time UTC+08:00
  • 古巴标准时 Cuba Standard Time UTC-04:00

MySQL中,如果time_zone为默认的SYSTEM值,则时区会继承为系统时区CST,MySQL内部将其认为是UTC+08:00。而jdbc会将CST认为是美国中部时间,这就导致会相差13小时,如果处在冬令时还会相差14个小时。

解决此问题的方法也很简单,我们可以明确指定MySQL数据库的时区,不使用引发误解的CST,可以将time_zone改为'+8:00',同时jdbc连接串中也可以增加serverTimezone=Asia/Shanghai。

3.4 如何避免出现时区问题

如何避免上述时区问题,可能你心里也有了些方法,简要总结几点如下:

  1. 首先保证系统时区准确。
  2. jdbc连接串中指定时区,并与数据库时区一致。
  3. time_zone参数建议设置为'+8:00',不使用容易误解的CST。
  4. 各环境数据库实例时区参数保持相同。

可能有的同学说了,我们数据库中time_zone参数选择的是默认的SYSTEM值,也没有发生程序时间和数据库时间不一致的问题。此时是否需要将time_zone改为'+8:00'?在这种情况下还是建议将time_zone改为'+8:00',特别是经常查询TIMESTAMP字段,因为当time_zone=system的时候,查询timestamp字段会调用系统的时区做时区转换,有全局锁__libc_lock_lock的保护,可能导致线程并发环境下系统性能受限。而改为'+8:00'则不会触发系统时区转换,使用MySQL自身转换,大大提高了性能。

总结:

读完本篇文章,你是否对数据库时区有了更深刻的认识呢。希望这篇文章对你有所帮助,特别是想了解MySQL时区相关内容时,可以拿来多读读。如果你遇到过其他时区相关问题,欢迎留言讨论。

一文解决MySQL时区相关问题的更多相关文章

  1. 解决mysql时区问题以及SSL问题

    看了下网上的教程,觉得都太麻烦啦,这里推荐个简单的! 解决时区问题 只需要加上serverTimezone=UTC即可,如下: spring.datasource.url=jdbc:mysql://1 ...

  2. 解决mysql时区与系统时区不一致问题。异常:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.

    异常信息:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone ...

  3. [flask实践] 解决qq邮箱/mysql的相关配置问题

    笔者经过flask web(Miguel著,封面是一条狗)一书的学习,打算实现一个旅游类网站,在此过程中发现,相对于书中的flasky博客程序,需要作出一些改变: 1. 注册邮箱:国内要使用126,q ...

  4. 永久解决IDEA 连接 mysql时区问题`

    永久解决IDEA 连接 mysql时区问题` 找到mysql的安装路径下的my.ini文件 加入以下代码 [mysqld] default-time_zone='+8:00' 关闭然后保存 打开然后以 ...

  5. Mysql优化相关总结

    Mysql优化相关总结 2016-05-31 数据库集中营 优化顺序: 选择适当的引擎和表结构和数据类型 建立索引,优化sql. 增加缓存,redis.memcache. 主从.主主,读写分离. my ...

  6. .Net DateTime跨时区相关问题

    项目:.Net CS结构,WCF通信,MySql存储. 场景:客户端(UTC+07:00)获取本地时间(DateTime对象)2017-01-17 15:20:12,通过WCF(http)传输至服务端 ...

  7. mysql数据库相关流程图/原理图

    mysql数据库相关流程图/原理图 1.mysql主从复制原理图 mysql主从复制原理是大厂后端的高频面试题,了解mysql主从复制原理非常有必要. 主从复制原理,简言之,就三步曲,如下: 主数据库 ...

  8. 解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题。 (默认mysql连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池。系统发布第二天访问链接关闭问题。

    解决Mysql连接池被关闭  ,hibernate尝试连接不能连接的问题. (默认MySQL连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池. 所以系统发布第二天访问会 ...

  9. RDS MySQL 全文检索相关问题的处理

    RDS MySQL 全文检索相关问题 1. RDS MySQL 对全文检索的支持 2. RDS MySQL 全文检索相关参数 3. RDS MySQL 全文检索中文支持 3.1 MyISAM 引擎表 ...

随机推荐

  1. 利用浏览器favicon的缓存机制(F-Cache)生成客户端浏览器唯一指纹

    利用浏览器favicon的缓存机制(F-Cache)生成客户端浏览器唯一指纹 首先介绍下: 这个技术出自 UIC论文:https://www.cs.uic.edu/~polakis/papers/so ...

  2. CPU 权限划分

    Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3.Windows只使用其中的两个级别RING0和RING3,RING0只给操作系统用,RING3谁都能用.如果普 ...

  3. PAT (Advanced Level) Practice 1002 A+B for Polynomials (25 分) 凌宸1642

    PAT (Advanced Level) Practice 1002 A+B for Polynomials (25 分) 凌宸1642 题目描述: This time, you are suppos ...

  4. Http请求状态码302,已得到html页面但未跳转?HttpServletRequest转发/HttpServletResponse重定向后,前端页面未跳转?Ajax怎么处理页面跳转?

    论断 出现此类错误,服务器端出现问题的可能性不大,大概率是前端问题. 问题概述 事情是这样的,我在用Java开发后端.前端页面使用jQuery库的 $.getJSON() 方法发送了一个Ajax请求. ...

  5. 敏捷史话(十一):敏捷宣言“间谍”——Steve Mellor

    Steve Mellor 是敏捷宣言的签署人之一,他自称是作为" 间谍"去参加雪鸟会议的. 起初收到会议邀请时,Steve 非常惊讶,因为他所做的工作一直都是关于建模方面的,很少将 ...

  6. 华为联运游戏或应用审核驳回:HMS Core升级提示语言类型错误

    问题描述 最近项目组应用集成华为的HMS Core SDK相关能力后,发布地区选择中国大陆,提交审核,华为审核驳回:在低于2.5.3版本的华为移动服务手机上启动时或调出支付时拉起升级提示为英文,正确的 ...

  7. Java【IO流、字节流、字符流】

    1.内存是临时存储 Input输入(读取) output输出(输出) 流:数据(字符字节)1个字符=2个字节 1个字节=8个二进制位 输入:把硬盘中的数据读取到内存中 输出:把内存中的数据写入到硬盘中 ...

  8. 什么?女神发了朋友圈,快来围观之Java设计模式:观察者模式

    目录 观察者模式 示例 定义 设计原则 意图 主要解决问题 何时使用 优缺点 女神和追求者的故事 Java中的实现 观察者模式 示例 微信公众号,关注就可以收到推送的消息,取消关注就不会收到 定义 定 ...

  9. 亮相 LiveVideoStackCon,透析阿里云窄带高清的现在与未来

    2021.4.16-4.17,阿里云视频云亮相 LiveVideoStackCon 音视频技术大会上海站,带来三场不同视角的主题演讲,并与众多行业伙伴一同交流.在 "编解码的新挑战与新机会& ...

  10. HUAWEI AppGallery Connect 正式发布移动端App,随时随地掌握应用动态

    华为应用市场AppGallery Connect应用一站式服务平台正式发布移动端App,帮助您随时随地查看应用信息,获取运营分析数据,接收重要消息通知,快速回复用户评论等,提升应用的运营管理效率,更便 ...