@Temporal(TemporalType.DATE) 与 Oracle 12

@Temporal(TemporalType.DATE) with Oracle 12

在我们的数据库中,我们有多个带有日期字段的实体。 Oracle 将每个日期视为相同的日期和时间部分。然而,JPA 实体通过注解 @Temporal 进行区分。当我们想省略时间部分时,我们用 @Temporal(TemporalType.DATE) 注释 Date 字段,Oracle 保存 00:00:00,如果没有,我们不带注释。

示例:

@Entity
public class MyEntity implements Serializable {
  private static final long serialVersionUID = 1L;

  @Id
  private long myentityId;

  @Temporal(TemporalType.DATE)
  private Date importantDate; //01.01.2015 00:00:00

  private Date creationDate; //01.01.2015 10:35:51
  ...
}

...
MyEntity me = new MyEntity();
me.setImportantDate(new Date());
me.setCreationDate(new Date());
...

我们从 Oracle 11 升级到 Oracle 12,现在 importantDate 的时间部分不再省略!

我使用完全相同的程序在两个数据库上对此进行了广泛测试。 这实际上破坏了我们的应用程序。

我该怎么做才能恢复以前的行为?


更新 1: 我缩小了问题范围:驱动程序 ojdbc6 12.1.0.1.0 有问题,ojdbc6 11.2.0.3.0 按预期工作。 (均使用 Oracle 12 数据库)

这是 11.1 中修复的时间戳问题的延续吗? (http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01)


更新 2: 由于Hibernate似乎不是问题所在,所以我用纯JDBC:

写了一个例子
OracleDataSource ods = new OracleDataSource();
...
Connection conn = ods.getConnection();
PreparedStatement ps = conn.prepareStatement("UPDATE MyEntity SET importantDate = ? WHERE myentityId = 4385");
ps.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
ps.execute();
...

在 ojdbc6 11.1 和 ojdbc6 12.1 之间切换时,此代码段的行为有所不同。

我们已经联系了 Oracle 支持,他们的回复如下(很遗憾,我无法提供 link 答案,因为需要 Oracle 支持帐户):

新行为按预期工作:

In JDBC 12.1.0.1, getDate and setDate do not truncate the time component of the date. This behavior is different to JDBC 11.2.0.X, where the time component is truncated. As per bug 14389749, 17228297 this change is deliberate and the 12c driver's behavior is correct.

解决方法为我提供了工作:

解决方法 #1: 修改应用程序以不插入时间组件(例如使用静态 UtilMethod)

public static Date truncateTime(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar.getTime(); }

解决方法 #2: 从 MOS 下载并应用补丁 19297927:(My Oracle Support)

  1. 单击补丁和更新选项卡。
  2. 输入上面的补丁号并点击搜索。
  3. 点击列表中与您的平台对应的补丁号
  4. 点击下载按钮下载补丁。
  5. 下载前请阅读所有适用的注意事项,然后单击“下载”按钮。

修补后替换 %Oracle_Home%\oracle_common\modules\oracle.jdbc_12.1.0 中的 ojdb7.jar 并将 -Doracle.jdbc.DateZeroTime=true 添加到您的 JVM Arguments