我有一个Java类,其字段定义为:
@Column
@NotNull
private LocalDate availabilityDate;
映射到定义为:
的列availability_date DATE NOT NULL
当我通过春季数据从保存前后从保存到MySQL数据库的日期进行比较时,我会在JUNIT中获得不同的结果:
Expecting:
<[InventoryAvailability(size=000, availabilityDate=2018-02-07, inventoryContextId=3847, quantity=15, lastChange=2018-02-08T14:32:24.770+01:00[Europe/Berlin]),
InventoryAvailability(size=001, availabilityDate=2018-02-07, inventoryContextId=3847, quantity=15, lastChange=2018-02-08T14:32:26.337+01:00[Europe/Berlin])]>
to contain exactly in any order:
<[InventoryAvailability(size=001, availabilityDate=2018-02-08, inventoryContextId=3847, quantity=15, lastChange=2018-02-08T14:32:26.337+01:00[Europe/Berlin]),
InventoryAvailability(size=000, availabilityDate=2018-02-08, inventoryContextId=3847, quantity=15, lastChange=2018-02-08T14:32:24.770+01:00[Europe/Berlin])]>
这怎么可能?我认为只有时间戳具有时区。我正在考虑将其存储为毫秒长或将UTC ZoneddateTime作为解决方法,但我怀疑我在这里不了解重要的东西。
我的答案是基于假设您正在使用java.time.localdate用于字段可用性。我编写了使用Spring Data和MySQL连接器(数据库版本为5.7.20-log(来重现您的案例的简单弹簧启动应用程序。
测试日期holderrepositorytest失败了,因为它不知道如何将localdate转换为迄今为止在数据库中。然后,我添加了对Hibernate-Java8的依赖性,测试变为绿色(如https://www.thoughts-on-java.org/hibernate-5-date-and-pime/,2(。
(。所以我的假设是,您的Junit测试有问题,或者可能与您的实体的平等和哈希码方法相连(COZ Hamcrest将在下面使用等价来比较类,并且从数据库类和创建的类中加载,只是不同的实验,默认对象等于方法将返回false(。and availabilitydate = 2018-02-08在您的问题中显示了没有时区的日期。
为了重现结果,我添加了测试应用程序的代码。我是我的日期持有人类,它具有ID和abotabolitydate,并包含基于字段ID的哈希码并等于实现:
package hello;
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
@Entity
public class DateHolder {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column
@NotNull
private LocalDate availabilityDate;
protected DateHolder() {}
public DateHolder(LocalDate availabilityDate)
{
this.availabilityDate = availabilityDate;
}
@Override
public String toString()
{
return String.format("DateHolder[id=%d, availabilityDate='%s']", id, availabilityDate);
}
public Integer getId()
{
return id;
}
public LocalDate getAvailabilityDate()
{
return availabilityDate;
}
@Override
public int hashCode()
{
return id;
}
@Override
public boolean equals(Object other)
{
if (other instanceof DateHolder)
{
return this.id == ((DateHolder)other).id;
}
else
{
return false;
}
}
}
这是我的JPA存储库:
package hello;
import org.springframework.data.repository.CrudRepository;
public interface DateHolderRepository extends CrudRepository<DateHolder, Long>
{
}
这是主要的春季启动应用程序类:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args)
{
SpringApplication.run(Application.class);
}
}
这是测试,它创建了2个日期持有人,将它们保存在数据库中,并将它们与数据库中的任何内容进行比较(它不在帐户中订单(。它还测试第一个实体的toString((方法的返回值,从数据库加载。
package hello;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import java.time.LocalDate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class DateHolderRepositoryTest
{
@Autowired
private DateHolderRepository repository;
@Test
public void testFindByLastName()
{
DateHolder dateHolder1 = new DateHolder(LocalDate.parse("2018-02-07"));
DateHolder dateHolder2 = new DateHolder(LocalDate.parse("2018-02-08"));
repository.save(dateHolder1);
repository.save(dateHolder2);
Iterable<DateHolder> dateHolders = repository.findAll();
assertThat(dateHolders, containsInAnyOrder(dateHolder2, dateHolder1));
assertThat(dateHolders.iterator().next().toString(), is("DateHolder[id=1, availabilityDate='2018-02-07']"));
}
}
只需使用适当的时区配置您的mySQL实例即可。如果您在容器上运行MySQL,则可能会遇到错误的时区,因此您会遇到这个怪异的DateTime值。
例如,如果您的JVM使用America/Sao_Paulo
时区,则可以将--default-time-zone=America/Sao_Paulo
发送到MySQL配置。这样,您将确保JVM和MySQL都在同一时区,而无需触摸Java应用程序。