不同的jdk版本的SQL查询行为不同

时间:2018-09-26 05:43:03

标签: java-8 oracle-sqldeveloper

我有一个oracle sql日期查询,该查询对于Java 7正常工作,但是当对Java 8运行相同的查询时,它将抛出错误,如下所示:
not a month”。
如果我使用查询,例如:
DATA_RECEIVED_MOMENT > TO_DATE ('26-09-18 10:33:43 AM', 'dd-mm-yy HH:MI:SS AM') 它适用于Java 8,但适用于Java 7
DATA_RECEIVED_MOMENT > '26-09-18 10:33:43 AM'
 甚至有效。
有人可以帮助解释这背后的原因是否是Java版本差异,其他所有内容都相同。我已经在Java 7中同时运行了查询。

1 个答案:

答案 0 :(得分:2)

您必须了解的一件事是,当您编写此代码时:

 DATA_RECEIVED_MOMENT > '26-09-18 10:33:43 AM'

您实际上是在说:

DATA_RECEIVED_MOMENT > TO_DATE('26-09-18 10:33:43 AM')

Oracle注意到您正在将字符串与日期进行比较...因此,由于您混合了梨和苹果,因此它隐式调用一个参数 TO_DATE sql函数。

此一参数TO_DATE函数使用由客户端软件设置的默认字符串格式:每个用户会话都可以设置所需的日期格式。没有固定的默认格式,因为它取决于您使用的客户端的语言设置(如果直接在服务器上工作,则取决于服务器操作系统的设置)。

换句话说:当您的查询与Java 7一起使用时,您很幸运,因为JDBC驱动程序可能正好设置了您隐式使用的默认字符串格式。

您使用的日期格式甚至在我的意大利Windows客户端上都无法使用(无需编写Java程序:您可以在SQL plus中尝试使用)

SQL>  select 1
  2   from dual
  3   where sysdate > '26-09-18 10:33:43 AM'
  4  /
     where sysdate > '26-09-18 10:33:43 AM'
                     *
 ERRORE alla riga 3:
 ORA-01843: mese non valido

之所以会发生这种情况,是因为为意大利客户安装程序初始化的默认日期格式为“ DD-MON-RR”(甚至不希望包含时间部分)

这是如何发现会话使用的日期时间格式。

 SQL> select *
   2  from nls_session_parameters
   3  where parameter = 'NLS_DATE_FORMAT'
   4  /

 PARAMETER                      VALUE
 ------------------------------ ----------------------------------------
 NLS_DATE_FORMAT                DD-MON-RR

您可以在Java程序中尝试此查询,以查看Java 8和Java 7之间的不同设置。

我的PC上的其他查询确实起作用:

从对偶中选择1,其中sysdate> '26 -set-18'

并且请注意,“ MON”的意思是“ 当月名称的第3个字符,以客户使用的语言表示”。  所以...如果我将操作系统切换为英语,那将无法正常工作。

因此:您将发现这很可能在您的Java 8应用程序中起作用:

 select 1 from dual where sysdate > 'DEC-20-18'

,但是您必须意识到,这仅适用于使用英语在美国安装的PC客户端。例如,在英格兰,他们写月的前一天。

所以好的做法是:

  1. 尽可能使用查询参数:避免在查询中写入文字值,并使用“ select * from mytable where date>?”
  2. 如果不可能使用1,则不要依赖于从字符串到日期或数字的隐式转换:始终对TO_DATE使用显式的twp参数调用,以指示日期格式(与Java 8一样)

无论如何,更好的选择是第一个,因为它在服务器上产生的负载更少:oracle保留已解析的所有查询的缓存:如果您输入1000次相同的EXACT查询文本(即使参数值是不同),它将在缓存中查找该文本已计算出的执行计划,并将检索执行该查询文本他已经为该查询文本(在这里我简化了事情)的访问计划的数据。

但是,如果您将查询文本中的查询值扩展为文字值,则迫使oracle重新执行文本的解析和执行计划的重新评估(这可能是占用大量CPU的操作)每次执行..而且您还会泛滥我之前描述的查询缓存。