【问题标题】:Persisting and updating date-time or timestamp of the database server via JPA通过 JPA 持久化和更新数据库服务器的日期时间或时间戳
【发布时间】:2016-05-02 04:34:03
【问题描述】:

当关联的数据库服务器和应用程序服务器运行在不同的时区时,检索、持久化和更新应用程序服务器的当前时刻并不是一个好方法。应始终要求数据库服务器代替应用程序服务器提供当前时间。

因此,在中间层 JPA 本身上执行以下操作将是错误的方法。

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

或者

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

或者

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

或者

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

等以及insertable = false, updatable = false 用于实体中的相应字段。

JPA 允许从数据库服务器检索日期时间/时间戳。

当然,JPQL 也是如此。

但是 JPA 似乎无法通过将持久化和合并当前时间的任务委托给数据库服务器本身来持久化和合并数据库服务器本身的当前时间。


我对使用@Version 装饰日期时间相关字段不感兴趣,因为它具有完全不同的目的,即在中间层 JPA 本身中获取行级乐观锁(反过来,使用时间戳本身的乐观锁也会受到某些问题的影响)特殊缺点)。

在中间层使用持久性提供程序时,我不太考虑 RDBMS 丛林。

所以,除了像 CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 这样的 RDBMS 所遵循的功能外,JPA 或特定的持久性提供程序本身是否有一种方法来处理数据库服务器的当前时间,用于两个幂等操作,即“持久”和“合并” “?

我目前关心的是 Hibernate 和 EclipseLink。

【问题讨论】:

  • 不应该Date class 和 jdbc driver 处理时区差异吗?你为什么要为此烦恼?
  • 这可能发生,如果数据库服务器和 EE 服务器/Servlet 容器都精确地运行在同一个时区(毫秒或秒的差异仍然可能)。然而,如果他们位于不同的时区,故事将完全改变。如果选择应用服务器的当前时间,依赖于当前时刻的数据库操作将严重失败。
  • 不,如果您正确使用Dates,他们不应该这样做。你试过了吗?
  • 例如,不同的应用服务器运行在不同的时区,如果试图访问一个普通的数据库服务器,如果应用服务器负责提交当前时间,那么当前时间被插入到数据库中根据应用程序服务器运行的不同时区而有所不同。在这些应用程序服务器中处理数据时间的 Java API 将根据它们使用的时区提交不同的时间。
  • 又错了。日期只不过是一个数字。时区(以及夏令时)仅在将该数字格式化为表示日期的文本时使用。你试过了吗?

标签: hibernate datetime jpa time timestamp


【解决方案1】:

我遇到了同样的问题,在两个地方解决了。

1) 在 Oracle 表中,我已将默认值添加到 SYSTIMESTAMP

"CREATION_DATE" TIMESTAMP (6) DEFAULT SYSTIMESTAMP 

使用SYSTIMESTAMP 而不是CURRENT_TIMESTAMPLOCALTIMESTAMP 很重要,因为它们都会使用调用者会话的语言环境!

2) 在 Entity 类中,对于我使用过的不应该更新的列:

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

这样做,生成的 INSERT 查询将不包括 Timestamp 列,因此数据库使用默认的 SYSTIMESTAMP 值。

对于可以更新的列,比如LAST_UPDATE 列,我想避免使用触发器,所以我不得不在 Spring Data 中编写一个自定义查询:

数据库

"LAST_UPDATE" TIMESTAMP (6) DEFAULT SYSTIMESTAMP 

实体

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

Spring 数据存储库

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

此解决方案不是独立于数据库的,但避免使用触发器并同步 Web 服务器时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 2021-04-19
    • 1970-01-01
    相关资源
    最近更新 更多