简体   繁体   中英

JPA EclipseLink PostgreSQL Insert java.time.LocalDate as java.sql.Date inserts wrong date

I'm getting a really strange behavior. I'm creating an Entity that has LocalDate fields, and inserting in the database, but the values in the database, are changed in some situations. This is the SQL it's logged with the debugger:

[EL Fine]: sql: 2016-11-19 21:31:57.979
--ClientSession(1809129176)--Connection(1261635736)
--Thread(Thread[main,5,main])
--INSERT INTO vcc_task (creator_user, execution_end_time, execution_start_time, last_edit_time, last_edit_user, server_name, state, thread_name, version, task_type, cc_service_id, vcc, start_time, end_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [user@vccModel1, null, null, 2016-11-20 00:31:46.016, user@vccModel1, , 0, , 1, 0, c1, vccModel1, 2017-05-06, 2017-05-07]

Note the " 2017-05-06, 2017-05-07 ". But if I query postgreSQL:

SELECT * FROM vcc_task

在此处输入图片说明

Other tests I wrote doesn't behave wrong. They save the correct date in the database. So, I'm pretty confuse.

If I query the database using the same EntityManager I used to store the taskEntity, I get an entity with the correct date. But if I query using a different EntityManager, I get the date from the database, that is one day before the correct date. That makes sense because the EM is returning from its cache. But I still don't understand who is transforming the Date, and why sometimes it does, and sometimes it doesn't.

For example, the following test pass using both LocalDate constructors:

  // private final LocalDate startTime = LocalDate.parse("2017-05-06");
  // private final LocalDate endTime = LocalDate.parse("2017-06-06");
  private final LocalDate startTime = Instant.parse("2017-05-06T00:00:00Z").atZone(ZoneOffset.UTC).toLocalDate();
  private final LocalDate endTime = Instant.parse("2017-06-06T00:00:00Z").atZone(ZoneOffset.UTC).toLocalDate();

  em = MyEntityManager.getEntityManager();
  final TaskDT tdt = new TaskDT(taskType, ccService, startTime, endTime, userName);
  t1 = new TaskEntity(userName, vcc, tdt);
  PersistLogic.persist(em, t1);
  em.close();

  em = MyEntityManager.getEntityManager();
  final TaskEntity t2 = em.find(TaskEntity.class, tid);
  em.close();

  Assert.assertNotNull(t2, "Task does exist");      
  Assert.assertEquals(t2.getVersion(), 1, "Resource Version");
  Assert.assertEquals(t2.getLastEditUser(), userName, "Resource Version");

  Assert.assertEquals(t2.getId().getVcc(), vcc, "getVcc");
  Assert.assertEquals(t2.getId().getTaskType(), taskType, "getTaskType");
  Assert.assertEquals(t2.getId().getCcService(), ccService, "getCcService");
  Assert.assertEquals(t2.getId().getStartTime(), startTime, "getStartTime");
  Assert.assertEquals(t2.getId().getEndTime(), endTime, "getEndTime");
  ...

在此处输入图片说明

The problem is happening when I create the Entity in the code:

// create the task
final LocalDate taskFromD = toLocalDate(tmpFrom);
final LocalDate taskToD = toLocalDate(tmpTo);
final TaskDT taskDT = new TaskDT(taskType, ccServiceName, taskFromD, taskToD, userName);
final TaskEntity newTask = new TaskEntity(userName, vccName, taskDT);

PersistLogic.persist(em, newTask);

It looks the same, but behaves different.

UPDATE

This is how I convert an Instant to LocalDate to pass to the Entity:

private static LocalDate toLocalDate(Instant i) {
   return i.atZone(ZoneOffset.UTC).toLocalDate();
}

This is the way I convert LocalDate to Date and back:

import java.sql.Date;
import java.time.LocalDate;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate locDate) {
        return (locDate == null ? null : Date.valueOf(locDate));
    }

    @Override
    public LocalDate convertToEntityAttribute(Date sqlDate) {
        return (sqlDate == null ? null : sqlDate.toLocalDate());
    }
}

Any help would be appreciated. Thanks

我猜问题是在convertToDatabaseColumn()方法中调用Date.valueOf(locDate),此处生成的瞬间是系统默认时区中该日期的午夜。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM