在我们的数据库中,我们有多个带有日期字段的实体。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()); ...
我们从甲骨文11升级到Oracle 12,现在的时间部分 importantDate 不再省略!
我使用完全相同的程序在两个数据库上对此进行了广泛的测试。这实际上破坏了我们的应用程序。
我该怎么做才能恢复以前的行为?
更新1:我缩小了范围:驱动程序ojdbc6 12.1.0.1.0出现了问题,ojdbc6 11.2.0.3.0可以正常工作。(都使用Oracle 12 DB)
这是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支持部门取得联系,他们的答复如下(很遗憾,由于需要Oracle支持帐户,因此我无法提供答案的链接):
新行为按预期工作 :
在JDBC 12.1.0.1中,getDate和setDate不会截断日期的时间部分。此行为与时间部分被截断的JDBC 11.2.0.X不同。根据错误14389749、17228297的更改,这是有意的,并且12c驱动程序的行为正确。
解决方法为我提供了工作:
解决方法#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)
After patching replace ojdb7.jar in %Oracle_Home%\oracle_common\modules\oracle.jdbc_12.1.0 and add -Doracle.jdbc.DateZeroTime=true to your JVM Arguments
%Oracle_Home%\oracle_common\modules\oracle.jdbc_12.1.0
-Doracle.jdbc.DateZeroTime=true