首页 > 解决方案 > Java:如何在没有时区转换的情况下将日期保存到 MySQL?

问题描述

我正在用 Java8 + MyBatis + MySQL5.7 来庆祝生日。我的代码是这样的:

// 'birthday' is a DATE column
@Insert("insert into MyTable (id, birthday) values (#{id"}, #{date})")
void saveDate(int id, LocalDate date);

@Select("select birthday from MyTable where id=#{id"}")
LocalDate loadDate(@Param("id") int id);

以及保存和加载日期的代码。

final int id = 1;
final LocalDate date = LocalDate.of(2020, 1, 3);

repo.saveDate(id, date);
LocalDate dateFromDB = repo.loadDate(id);

System.out.println(date);        // 2020-1-3
System.out.println(dateFromDB);  // 2020-1-2

我注意到“dateFromDB”的值总是比“日期”早一天。我认为这是由时区转换引起的。由于我的应用程序是 UTC+8,而 DB 使用的是 UTC。通过使用 DATETIME 而不是 DATE,我可以看到日期“2020-1-3”保存为“2020-1-2 16:0:0”。

所以问题是如何在保存生日等日期时避免时区转换?

----------------- 更新于 2020-02-20 ---------------------------------------- ---------

到目前为止,我找到了 4 种方法来做到这一点:

  1. 添加参数noTzConversionForDateType=true以避免仅对日期类型进行转换。这是最好的方法,但它只适用于 5.1 版本。我真的不明白为什么从 8.0 版中删除它...(文档
  2. 添加一个参数serverTimezone=GMT%2B8,使用客户端时区 (UTC+8) 作为服务器时区。转换仍然发生,但没有任何改变。问题是TIMESTAMP列也会受到影响。
  3. -Duser.timezone=UTC向 JVM添加参数。问题类似于#2。
  4. 发送LocalDate值作为String。更新saveDate函数如下(仅将类型从 更改LocalDateString):
@Insert("insert into MyTable (id, birthday) values (#{id"}, #{date})")
void saveDate(int id, String date);

然后String在调用之前将日期转换为saveDate

String dateString = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
repo.saveDate(id, dateString);

请注意,DB 中的数据类型仍然是DATE. 这种方式的好处是只有birthday列会受到影响。问题是代码不优雅,可能会导致大型数据集的性能问题。

标签: javamysqltimezonemybatislocaldate

解决方案


假设您使用如下连接字符串连接到 MySQL

jdbc:mysql://localhost/mydb?useLegacyDatetimeCode=false&serverTimezone=YOUR_TZ

应该为你做一些转换


推荐阅读