ResultSet#getDate()语义

时间:2013-07-10 13:52:08

标签: java oracle datetime jdbc

我们从ojdbc6-11.2.0.3.0迁移到ojdbc7-12.1.0.1并观察到ResultSet#getDate()语义的变化。之前返回的java.sql.Date将被标准化'通过根据java.sql.Date上指定的合同将小时,分钟,秒和毫秒设置为零。使用ojdbc7时不再是这种情况,java.sql.Date根据数据库中的值设置小时,分钟,秒和毫秒。

我查看了ResultSet#getDate()的Javadoc,并没有明确说出哪些行为是正确的。我会假设旧的行为符合规范的意图。我对吗?我们遇到过驱动程序错误吗?

3 个答案:

答案 0 :(得分:11)

这显然是一个错误,因为类java.sql.Date的文档说明了

  

为了符合SQL DATE的定义,java.sql.Date实例包含的毫秒值必须通过在特定时区中将小时,分钟,秒和毫秒设置为零来“标准化”。实例是关联的。

答案 1 :(得分:7)

Oracle没有改变JDBC规范。我们更新了Oracle Database JDBC驱动程序文档。如果文档中有任何令人困惑或不正确的内容,我们将解决此问题。但是,没有更改JDBC规范。

以前版本的驱动程序不一致。在某些地方,他们将秒数归零。在其他地方他们没有。在12.1中,我们使驱动程序保持一致。问题是,什么是正确的行为。无论哪种方式,一些客户都会看到行为的变化。

经过长时间的激烈辩论,我们认为Oracle数据库客户最好的办法是不要将秒数归零。让我解释一下。

  • ANSI SQL DATE类型不存储秒数。 JDBC规范主要采用ANSI SQL。
  • Oracle数据库DATE类型确实存储秒数。 ANSI SQL委员会成员向我保证,这完全符合ANSI SQL。
  • JDBC的目标是公开数据库。 JDBC规范没有定义一些抽象数据库,其目的是驱动程序实现该抽象数据库。 JDBC驱动程序需要公开数据库的详细信息,而不是隐藏它们。 JDBC定义了抽象一些数据库细节的工具,但程序员可以选择使用或不使用这些工具。
  • java.sql.Date虽然很容易,但却没有强制执行零秒行为。该计划的责任在于强制执行或不强制执行该行为。

所以,Oracle DATE有几秒钟。 Oracle JDBC驱动程序公开Oracle数据库。如果getDate将秒数归零,则会丢失数据。对于一些用户来说,这无关紧要,但对于其由于Oracle DATE在DATE列中存储了许多Oracle数据库存储时间,并具有第二精度。在这些情况下将秒数归零会丢失信息。

如果程序将非零秒的日期传递给setDate,则程序创建了一个不合规的日期。如果驱动程序将秒数归零,则驱动程序会丢弃程序提供的信息以及数据库可以存储的信息。司机再次失去了信息。

编写SQL或Java以将get和set的秒数归零是很容易的。尽管当然可能,但更难以解决丢失信息的问题。

所以我们选择让驱动程序始终保持java.sql.Date秒。 ResultSet.getDate可以构造一个非零秒的java.sql.Date,但这可以准确反映数据库中的内容。如前所述,Date的实施可以强制执行,但没有。查看它的一种方法是程序在将数据存储在数据库中时创建了Date,因此它是程序的责任。驱动程序只是使用程序提供的数据。

我真的很抱歉以前司机不一致。我们一直在努力清理不一致和奇怪的角落案件。但我们拥有庞大的安装基础。每次我们改变某些东西,甚至是明显的错误修复,某些客户都会受到影响。因此,我们尝试在改进驱动程序和保持向后兼容性之间取得平衡。 12c是主要版本。我们借此机会进行了一些更明显的变化。我们对这次中断感到遗憾,但认为这对整体客户来说是正确的。

答案 2 :(得分:0)

我在11g数据库上分析了这个问题,可以确认shonky linux用户提到的PreparedStatement.setDate(index, java.sql.Date)的行为(我测试了ojdbc6-11.2.0.4-gojdbc7-12.1.0.2)。

虽然新行为可能显式违反了JDBC规范,但它肯定不符合java.sql.Datejava.sql.Time和{{1}的概念。 }以及相应的数据类型java.sql.TimestampTypes.DATETypes.TIME

因此,就“现有Oracle客户的痛苦减少”而言,Douglas Surber所解释的决定可能有意义,从(DBMS独立的)JDBC角度来看似乎并不正确。