2

When the associated database server and the application server are running on different time zones, retrieving, persisting and updating the current instant of time of the application server is not a good way to go. The database server should always be asked for the current time in place of the application server.

Thus, doing like the following on the middle tier JPA itself would be a wrong way to go.

Entity entity = new Entity();
entity.setTimestamp(new Timestamp(new java.util.Date().getTime()));
// Persist or merge the entity.

Or

Entity entity = new Entity();
entity.setLocalDateTime(java.time.LocalDateTime.now(ZoneOffset.UTC));
// Persist or merge the entity.

Or

Entity entity = new Entity();
entity.setZonedDateTime(java.time.ZonedDateTime.now(ZoneOffset.UTC));
// Persist or merge the entity.

Or

Entity entity = new Entity();
entity.setDateTime(org.joda.time.DateTime.now(org.joda.time.DateTime.DateTimeZone.UTC));
// Persist or merge the entity.

etc along with insertable = false, updatable = false for the respective field in the entity.

JPA allows the retrieval of date-time / timestamp from the database server.

Naturally, the same is true for JPQL as well.

But there seems no way which JPA can exhibit to persist and merge the current time of the database server itself by delegating the task of persisting and merging the current time to the database server itself.


I am not interested in decorating date-time related fields with @Version as it has a completely different purpose of acquiring a row level optimistic lock in the middle tier JPA itself (optimistic locking using timestamp itself in turn also suffers from certain special drawbacks).

I do not much consider the jungle of RDBMS while using a persistence provider in the middle tier.

So, except for the functionality being adhered to RDBMS like CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, does JPA or a particular persistence provider itself has a way to deal with the current time of the database server for two idempotent operations namely "persist" and "merge"?

I am currently concerned with Hibernate and EclipseLink.

Tiny
  • 27,221
  • 105
  • 339
  • 599
  • Shouldn't `Date` class and jdbc driver take care of time zone difference? Why are you bothering with that? – Dragan Bozanovic Jan 25 '16 at 18:56
  • That may happen, if the database server and the EE server / Servlet container both precisely run on the same time zone (difference in milliseconds or seconds is still likely). The story will however completely change, if they are located at different time zones. Database operations depending upon the current time instant will severely fail, if the current time of the application server is chosen. – Tiny Jan 25 '16 at 19:07
  • No, they shouldn't, if you are using `Date`s properly. Did you try it? – Dragan Bozanovic Jan 25 '16 at 19:18
  • For example, different application servers running in different time zones, if attempted to access a common database server and if the application servers were responsible for submitting the current time, then the current time being inserted into the database would be different according to different time zones which the application servers are running in. The Java APIs handling data-time in those application servers would submit different time based on the time zone they use. – Tiny Jan 25 '16 at 20:00
  • Wrong again. Date is nothing more than a number. Time zone (daylight saving time as well) is used only when formatting that number to a text representing the date. Did you try it? – Dragan Bozanovic Jan 25 '16 at 21:07
  • In [this](https://wikigurus.com/Article/Show/114266/How-to-store-a-javautilDate-into-a-MySQL-timestamp-field-in-the-UTC-or-GMT-timezone) bog, they recommend to synchronize clocks with [Network Time Protocol (NTP)](https://en.wikipedia.org/wiki/Network_Time_Protocol) or rely only upon the database server's current time. I don't know whether they are wrong. This is also available on [this site](http://stackoverflow.com/a/311522/1391249). – Tiny Jan 27 '16 at 11:26
  • Clock synchronization is another thing and relates to machines in the same time zone as well. – Dragan Bozanovic Jan 27 '16 at 11:30
  • Did you find an answer to this? I am also interested. – vulkanino Sep 27 '17 at 07:54
  • @vulkanino : No, sorry. I am still waiting. – Tiny Sep 27 '17 at 09:34

1 Answers1

1

I had the same problem and solved it in two places.

1) In the Oracle table I've added the default value to SYSTIMESTAMP

"CREATION_DATE" TIMESTAMP (6) DEFAULT SYSTIMESTAMP 

It is important to use SYSTIMESTAMP and not CURRENT_TIMESTAMP or LOCALTIMESTAMP because they both would use the caller session's locale!

2) In the Entity class, for columns that should never be updated I've used:

@Column(name = "CREATION_DATE", insertable=false, updatable = false)
public Timestamp getCreationDate() 
{
    return creationDate;
}

By doing so, the resulting INSERT query won't include the Timestamp column so the database uses the default SYSTIMESTAMP value.

For columns that could be updated, say a LAST_UPDATE column, I wanted to avoid the use of triggers, so I had to write a custom query in Spring Data:

DB

"LAST_UPDATE" TIMESTAMP (6) DEFAULT SYSTIMESTAMP 

Entity

@Column(name = "LAST_UPDATE", insertable=false, updatable = true)
public Timestamp getLastUpdate() 
{
    return lastUpdate;
}
...

Spring Data Repository

@Modifying
@Query(value="update User u set u.lastUpdate=SYSTIMESTAMP where u.id=:userId")
void setLastUpdateTime(@Param("userId") int userId);

This solution is not db-independent but avoids to use triggers and to synchronize the web servers time.

vulkanino
  • 9,074
  • 7
  • 44
  • 71