保存到 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();

【问题讨论】:

Java LocalDate 对象不存储时间或时区信息(请参阅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 映射到您的数据库架构中,并使用AttributeConverterLocalDate 转换为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 更改的主要内容,如果未能解决你的问题,请参考以下文章

MS Access DAO 连接在退出时放弃更改

如何在保存 PDF 表单时阻止 Adob​​e Reader 询问“另存为”(即只允许“保存”)?

如何阻止 textarea 标签翻译数字

如何阻止实体框架尝试保存/插入子对象?

如何使用 PHP 将非英文字符正确保存到 MySQL 数据库中?

如何阻止 IntelliJ IDEA 从 .properties 文件中删除空行?