注意:以下所有的内容,是通过实验得出,并进行总结,如有错误,请指正
前置知识
@DateTimeFormat 和 @JsonFormat 的详细研究,以及timezone="GMT+8"的研究,时区问题(1)
因为有了前置知识,所以这篇也很好理解,讨论一下内容
- mysql 数据库的时区问题
- serverTimeZone 到底什么作用。
实验开始
场景描述:
- mysql 的时区在东4区,web服务器的时区在东8区,存东8区的日期到东4区的mysql服务器,并且再取出来。
实验1
- 修改mysql 的时区。
SET GLOBAL time_zone = '+4:00';
SET time_zone = '+4:00';
SHOW VARIABLES LIKE "%time_zone%";
- 配置
- 数据库连接url(未指定serverTimeZone)
jdbc:p6spy:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=UTF-8&&useSSL=false&useUnicode=true
- web服务器controller代码,以及发送http请求的运行结果。
@PostMapping("put")
public String put(){
User user = new User();
Date date = new Date();
System.out.println(date); // Sat Mar 07 21:36:04 CST 2020
user.setDate(date);
System.out.println(user); // User(id=null, date=Sat Mar 07 21:36:04 CST 2020)
userMapper.insert(user); // INSERT INTO mybatis_plus.user ( id, date ) VALUES ( 1236284482563080193, '2020-03-07T21:36:04.321+0800' )
System.out.println(userMapper.selectById(user.getId())); // User(id=1236284482563080193, date=Sat Mar 07 21:36:04 CST 2020)
return "okPost";
}
结果分析,目前看起来都挺好。
- mysql服务器
- 问题来了:
我传的是21点,怎么存进去成了17点。 - 结果分析:
mysql的时区是东4区,web服务器的时区是东8区,Web服务器在执行SQL的时候,传入日期字符串是这样的 ‘2020-03-07T21:36:04.321+0800’ ,也就是这是一个东8区的日期字符串。(这点有些问题,问题是,插入的时候转成东4区时间的操作是发生在web服务器端,还是发生在mysql服务器端。但是这并不影响后续的测试。mysq服务器无法插入有时区标识的时间字符串,所以假设是发生在web服务器端。)
web服务器端 分析你mysql在东4区,我比你快4个小时,也就是你是,21-4=17,存的时候也就是17点。
实验1.1,从数据库,取值
- web controller 代码,以及测试结果
@GetMapping("user")
public String get(@RequestParam Long id){
String dateString = userMapper.getDateString(id); // select date from user where id = 1236284482563080193
System.out.println(dateString); // 2020-03-07 17:36:04
Date date = userMapper.getDate(id); // select date from user where id = 1236284482563080193
System.out.println(date); // Sat Mar 07 21:36:04 CST 2020
User user = userMapper.selectById(id); // SELECT id,date FROM mybatis_plus.user WHERE id=1236284482563080193
System.out.println(user); // User(id=1236284482563080193, date=Sat Mar 07 21:36:04 CST 2020)
return "okGet";
}
结果分析:
- 数据库的时间是 2020-03-07 17:36:04,用String类型接收,结果就是数据库的日期。可知对取出日期时的转换,由数据库时区时间转换成web服务器时区的时间,不是发生在数据库,而是发生在web服务器。
- 转成Date的日期,比数据库的快了4小时,原因是数据库是东4区,而web服务器是东8区,东8比东4时间快4小时。
问题是:为什么web服务器知道mysql服务器是东4区?
- 我认为是web服务器在与数据服务器连接的时候,就获取到数据库的时区,如果数据库的时区未设置,为空,那么web服务器根本无法连接,数据库服务器,会出现错误日志,让指定 serverTimeZone。
问题又来了:serverTimeZone 的作用是什么呢?
探索 serverTimeZone 的作用
实验2,向mysql服务器添加数据
之前的配置web服务器在东8区,mysql时区是东4区,依旧不变,
现在修改web服务器端的url连接:(修改为GMT+8)
jdbc:p6spy:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=UTF-8&&useSSL=false&serverTimezone=GMT%2B8&useUnicode=true
- web服务器controller,以及执行结果
@PostMapping("put")
public String put(){
User user = new User();
Date date = new Date();
System.out.println(date); // Sat Mar 07 21:57:31 CST 2020
user.setDate(date);
System.out.println(user); // User(id=null, date=Sat Mar 07 21:57:31 CST 2020)
userMapper.insert(user); // INSERT INTO mybatis_plus.user ( id, date ) VALUES ( 1236289879764172801, '2020-03-07T21:57:31.123+0800' )
System.out.println(userMapper.selectById(user.getId())); // User(id=1236289879764172801, date=Sat Mar 07 21:57:31 CST 2020)
return "okPost";
}
结果分析:
- 看起来没什么问题
- mysql服务器
结果分析:
- 结果正确。
实验2.1 ,从服务器获取数据
- web服务器controller,以及执行结果
@GetMapping("user")
public String get(@RequestParam Long id){
String dateString = userMapper.getDateString(id); // select date from user where id = 1236289879764172801
System.out.println(dateString); // 2020-03-07 21:57:31
Date date = userMapper.getDate(id); // select date from user where id = 1236289879764172801
System.out.println(date); // Sat Mar 07 21:57:31 CST 2020
User user = userMapper.selectById(id); // SELECT id,date FROM mybatis_plus.user WHERE id=1236289879764172801
System.out.println(user); // User(id=1236289879764172801, date=Sat Mar 07 21:57:31 CST 2020)
return "okGet";
}
结果分析:
- 结果正确
总结
serverTimeZone的作用就是指定web服务器和mysql服务器的会话期间的mysql服务器时区,就是临时指定mysql服务器的时区。
PS
如果帮助到你的话,点个赞鼓励下,欢迎加入我的置顶博客的javaweb交流群,不搞带课推广,让我们一起向诗靠拢。