java - 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 种方法来做到这一点:
- 添加参数
noTzConversionForDateType=true
以避免仅对日期类型进行转换。这是最好的方法,但它只适用于 5.1 版本。我真的不明白为什么从 8.0 版中删除它...(文档) - 添加一个参数
serverTimezone=GMT%2B8
,使用客户端时区 (UTC+8) 作为服务器时区。转换仍然发生,但没有任何改变。问题是TIMESTAMP
列也会受到影响。 -Duser.timezone=UTC
向 JVM添加参数。问题类似于#2。- 发送
LocalDate
值作为String
。更新saveDate
函数如下(仅将类型从 更改LocalDate
为String
):
@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
列会受到影响。问题是代码不优雅,可能会导致大型数据集的性能问题。
解决方案
假设您使用如下连接字符串连接到 MySQL
jdbc:mysql://localhost/mydb?useLegacyDatetimeCode=false&serverTimezone=YOUR_TZ
应该为你做一些转换