保存到 mySQL 数据库时如何阻止 LocalDate 更改
Posted
技术标签:
【中文标题】保存到 mySQL 数据库时如何阻止 LocalDate 更改【英文标题】:How to stop LocalDate from changing when being saved to a mySQL database 【发布时间】:2018-03-08 20:47:38 【问题描述】:使用 JPA CriteriaBuilder API 将 LocalDate
字段(例如“2017-09-27”)保存到 mysql Date
列时,结果不同(例如“2017-09-26”)。
我已使用 SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)
验证我的数据库的时区设置为 UTC,因为结果是 '00:00:00'。
我在本地对此进行测试,并且我的时区为 GMT + 2,所以我怀疑当从 LocalDate
转换到 Date
时,会扣除 2 小时并在日期前 1 天生成日期请求的日期(假设 LocalDate
字段,由于它没有没有时间信息,被视为 00:00:00。
在这种情况下保存 LocalDates 的最佳方法是什么?我是否应该遵循https://***.com/a/29751575/3832047 此处的建议并将所有 LocalDate 字段明确设置为 UTC 或类似的东西?
我进行了测试,看看在代码中转换它们时会发生什么,并得到以下结果:
Date convertedDate = Date.valueOf(localDate);
conversion-result
编辑
这是我用来检索数据的代码示例,其中也发生了奇数日期更改。如果我请求2017-06-27
的数据,我会收到2017-06-26
的结果。
CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(HorseAndTrailerRequest.class);
Root<HorseAndTrailerRequest> criteria = criteriaQuery.from(HorseAndTrailerRequest.class);
ParameterExpression<LocalDate> effectiveDateParameter = criteriaBuilder.parameter(LocalDate.class);
criteriaQuery.select(criteria)
.where(
criteriaBuilder.equal(criteria.get("effectiveDate"), effectiveDateParameter)
);
TypedQuery<HorseAndTrailerRequest> query = sessionFactory.getCurrentSession().createQuery(criteriaQuery);
query.setParameter(effectiveDateParameter, date);
return query.getResultList();
【问题讨论】:
JavaLocalDate
对象不存储时间或时区信息(请参阅Javadoc],我怀疑还有别的东西。
您能否尝试运行以下命令来确认您的 MySQL 服务器时区:SELECT @@system_time_zone, NOW(), UTC_TIMESTAMP()
@TimBiegeleisen 结果是UTC | 2017-09-27 11:28:51 | 2017-09-27 11:28:51
。
我赞成你的问题,但在这一点上,我认为我们需要查看将本地日期保存到 MySQL 中的 Java 代码。
好的,谢谢,它也发生在读取上 - 当查询请求来自“2017-09-27”的数据时,我只接收来自“2017-09-26”的数据,非常奇怪的行为.我将通过阅读示例来编辑问题。
【参考方案1】:
由于LocalDate
没有TimeZone,您可以将column_date 映射到您的数据库架构中,并使用AttributeConverter
将LocalDate
转换为long 以避免时区转换问题:
import javax.persistence.Converter;
import java.time.LocalDate;
import javax.persistence.AttributeConverter;
@Converter
public class LocalDateToLong implements AttributeConverter<LocalDate, Long>
@Override
public Long convertToDatabaseColumn(LocalDate date)
if (date != null)
long epochDay = date.toEpochDay();
return epochDay;
return null;
@Override
public LocalDate convertToEntityAttribute(Long epochDay)
// TODO Auto-generated method stub
if (epochDay != null)
LocalDate date = LocalDate.ofEpochDay(epochDay);
return date;
return null;
【讨论】:
【参考方案2】:我遇到了同样的问题,我在看到 hibernate atlassian 问题时解决了它(这里是线程:https://hibernate.atlassian.net/browse/HHH-11396)。你有两种选择:
使用-Duser.timezone=Europe/Berlin
或通过TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
以编程方式设置JVM
创建一个分区的 DateTime,然后将其转换回 Date
public static final ZoneId ZONE_EUROPE_BERLIN = ZoneId.of("Europe/Berlin");
@Override
public Date convertToDatabaseColumn(LocalDate locDate)
if (locDate == null)
return null;
ZonedDateTime zonedDateTime = locDate.atStartOfDay(ZONE_EUROPE_BERLIN);
LocalDate producerLocalDate = zonedDateTime.toLocalDate();
Date date = Date.valueOf(producerLocalDate);
return date;
我使用了第二种选择。
【讨论】:
以上是关于保存到 mySQL 数据库时如何阻止 LocalDate 更改的主要内容,如果未能解决你的问题,请参考以下文章
如何在保存 PDF 表单时阻止 Adobe Reader 询问“另存为”(即只允许“保存”)?