MySQL的LocalDate持久性可以追溯到更早的日期

时间:2019-01-22 13:40:17

标签: mysql spring hibernate java-8 jpa-2.0

我已经看到这个问题在StackOverflow上发布了好几次,并且大多数带有Spring Boot Configuration的Spring Boot应用程序都遇到了这个问题。我已按照所有步骤进行操作,但仍然存在此问题。如果无法尽快解决此问题,则必须返回到旧的java.util.Date才能将我的数据持久保存到数据库中……至少它可以正常工作。因此,我有一个Spring 5.1.2.Release应用程序,具有Hibernate 5.4.0.Final,hibernate-java8依赖项和最新的MySQL Connector 8.0.13。

从网上的先前文章和其他文章中我了解到,如果数据库设置为UTC,但该应用程序在另一个时区(以我的情况为EST的GMT-5)运行,则可能会出现此问题。

因此,以下是技术细节: 我的MySQL连接看起来像:

hibernate.connection.url=jdbc:mysql://localhost:3306/my_db? 
serverTimezone=UTC&useLegacyDatetimeCode=false&useTimezone=true

在applicationContext.xml中使用连接字符串:

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
        <value>${hibernate.connection.driver.class}</value>
    </property>
    <property name="url">
        <value>${hibernate.connection.url}</value>
    </property>
    <property name="username">
        <value>${hibernate.connection.username}</value>
    </property>
    <property name="password">
        <value>${hibernate.connection.password}</value>
    </property>
</bean>

我的applicationContext.xml中的Hibernate属性如下:

<property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            <prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop>
            <prop key="useUnicode">true</prop>
            <prop key="useLegacyDatetimeCode">false</prop>
            <prop key="serverTimezone">UTC</prop>
            <prop key="useTimezone">true</prop>
            <prop key="hibernate.jdbc.time_zone">UTC</prop>
        </props>
    </property>

我的Maven依赖项是:

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.4.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-java8</artifactId>
        <version>5.4.0.Final</version>
    </dependency>

我的实体代码很简单:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "transaction_id")
private long txId;

@Column(name = "transaction_date")
private LocalDate txDate;

我这样将代码保存到数据库中:

@Override
public TxEntity create(TxEntity txEntity)
{
    this.sessionFactory.getCurrentSession().save(txEntity);
    this.sessionFactory.getCurrentSession().flush();
    this.sessionFactory.getCurrentSession().refresh(txEntity);
    return txEntity;
}

数据库在MySQL中具有“ transaction_date”作为DATE字段。

我的单元测试表明我可以创建一个新记录,并且我将日期设置如下:

      LocalDate today = LocalDate.now();

我保留记录,并在进行测试时:

assertEquals(today, myRecord.getTransactionDate());

这失败了,因为我得到了上一个日期。

我认为,如果我使用最新版本的Hibernate和Hibernate-java8,我会没事的,但事实并非如此。我以为如果我安装了最新的JPA2.2,它将起作用,但事实并非如此。因此,我认为我做的所有事情都正确,但仍然存在问题。

因此,如果您需要查看任何内容,请告诉我,然后我可以添加。我认为我所做的一切都很好,但是如果有什么需要修复的地方,请告诉我。当然,我将继续自己研究这个问题。

2 个答案:

答案 0 :(得分:0)

如果您不想触摸Java项目或连接字符串来解决此问题,则可以直接配置MySQL时区。在我的计算机上,JVM时区是正确的(America / Sao_Paulo),因此将其更改为UTC以解决与MySQL的冲突是不可行的。

我遇到的问题仅在于MySQL时区配置。由于我在容器上运行MySQL,因此得到了错误的默认时区。解决方法是将--default-time-zone=America/Sao_Paulo传递给MySQL容器配置,从而解决了此问题。现在,MySQL和JVM都具有相同的时区。

答案 1 :(得分:0)

对我来说,经过一段时间的调试,我注意到Mysql时区是UTC,但是我的默认jvm时区可以通过以下方式看到:

public class DefaultTimeZone {
    public static void main(String[] args) {
        System.out.println(java.util.TimeZone.getDefault().getID());
    }
} 

是美国/蒙特利尔,因此在启动应用程序时更新了我的ide(IntellJ)设置以将-Duser.timezone = UTC作为参数传递。 (当然,还有很多其他方法可以做到这一点,但就我而言,这足够了)