ResultSet#getDate()语义

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

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

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

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

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

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

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

  • ANSI SQL DATE类型不存储秒。 JDBC规范主要采用ANSI SQL。
  • Oracle Database 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是主要版本。 我们借此机会做出了一些更明显的变化。 我们对这次中断感到遗憾,但认为这对整体客户来说是正确的。

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

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

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