8

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

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

4

3 回答 3

11

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

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

于 2013-07-10T14:10:56.987 回答
7

Oracle 不会更改 JDBC 规范。我们更新了 Oracle 数据库 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 存储秒,因此许多 Oracle 数据库在 DATE 列中存储具有秒精度的时间。在这些情况下将秒归零会丢失信息。

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

编写 SQL 或 Java 将 get 和 set 的秒数归零很容易。尽管肯定有可能,但要解决丢失信息的问题更加困难。

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

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

于 2014-03-24T16:38:24.807 回答
0

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

虽然新行为可能没有明确违反 JDBC 规范,但它肯定不适合具有java.sql.Datejava.sql.Timejava.sql.Timestamp相应数据类型Types.DATETypes.TIME和的概念Types.TIMESTAMP

因此,尽管就“为现有 Oracle 客户减轻痛苦”而言,Douglas Surber 解释的决定可能是有道理的,但从(独立于 DBMS 的)JDBC 角度来看,它似乎并不正确。

于 2015-01-22T17:47:23.590 回答