2008-12-20 49 views
13

我目前正在使用來自Java的iBATIS來處理Oracle SQL DATE轉換問題。通過Java使用iBATIS的Oracle SQL DATE轉換問題JDBC

正在使用Oracle JDBC瘦驅動程序ojdbc14版本10.2.0.4.0。 iBATIS版本2.3.2。 Java 1.6.0_10-rc2-b32。

問題圍繞着正在由這個片段SQL的返回DATE類型的列:

SELECT * 
FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) order by from_date 

封裝過程調用返回一個引用遊標被包裝在一個表中,以在那裏然後容易讀取結果集,就像對錶進行選擇查詢一樣。

在PL/SQL開發人員,其中一列返回,FROM_DATE,SQL日期型,具有精度一天的時間:

Tue Dec 16 23:59:00 PST 2008 

但是當我通過iBATIS的和JDBC,值訪問此只當顯示像這樣

Tue Dec 16 12:00:00 AM PST 2008 

這是清晰的:

本來應該是:

保留精度天
1229500740000 milliseconds since epoch 
Tuesday, December 16, 2008 11:59:00 PM PST 

但是,讓這個代替:

1229414400000 milliseconds since epoch 
Tuesday, December 16, 2008 12:00:00 AM PST 
(as instance of class java.sql.Date) 

無論我怎麼努力,我不能公開此日期列全精度通過Java JDBC和iBATIS歸還。

什麼iBATIS的是從映射是這樣的:

FROM_DATE : 2008-12-03 : class java.sql.Date 

當前iBATIS的映射是這樣的:

<result property="from_date" jdbcType="DATE" javaType="java.sql.Date"/> 

我也試過:

<result property="from_date" jdbcType="DATETIME" javaType="java.sql.Date"/> 

<result property="from_date" jdbcType="TIMESTAMP" javaType="java.sql.Timestamp"/> 

但所有嘗試的映射都會產生相同的截斷日期值。就好像JDBC在iBATIS甚至觸及它之前已經做了丟失數據精度的損害。

顯然,當我留在PL/SQL Developer中運行相同的SQL代碼段作爲測試腳本時,通過JDBC和iBATIS不會發生我的一些數據精度。根本不可接受,非常令人沮喪,並最終非常可怕。

回答

8

完整信息(和它比這裏所描述和可能取決於其在Oracle驅動程序的特定版本都在使用更復雜的)是理查德·耶的answe [R在這裏 - [現已過期鏈接Nabble]


快速抓住它從nabble到期前...

羅傑, 見:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01

具體做法是: 簡單數據類型 是什麼繼續與DATE和TIMESTAMP? 本節介紹簡單的數據類型。 :-)

在9.2之前,Oracle JDBC驅動程序將DATE SQL類型映射到java.sql.Timestamp。這有一定的意義,因爲Oracle DATE SQL類型包含日期和時間信息,就像java.sql.Timestamp一樣。對java.sql.Date的映射更明顯是有點問題,因爲java.sql.Date不包含時間信息。 RDBMS也不支持TIMESTAMP SQL類型,所以將DATE映射到Timestamp沒有問題。

9.2在TIMESTAMP支持被添加到RDBMS。 DATE和TIMESTAMP的區別在於TIMESTAMP包含納秒,DATE不包含。因此,從9.2開始,DATE被映射到Date並且TIMESTAMP被映射到Timestamp。不幸的是,如果您依賴DATE值來包含時間信息,則存在問題。

有解決這個問題的幾種方法:

改變你的表使用TIMESTAMP,而不是過時了。這很可能是不可能的,但它是最好的解決方案。

改變您的應用程序以使用defineColumnType將列定義爲TIMESTAMP而不是DATE。有這樣的問題,因爲你真的不想使用defineColumnType,除非你必須(請參閱什麼是defineColumnType,我應該什麼時候使用它?)。

改變你的應用程序使用getTimestamp而不是getObject。如果可能的話,這是一個很好的解決方案,但是很多應用程序都包含依賴於getObject的泛型代碼,因此並不總是可行的。

設置V8Compatible連接屬性。這告訴JDBC驅動程序使用舊映射而不是新映射。您可以將此標誌設置爲連接屬性或系統屬性。您可以通過將連接屬性添加到傳遞給DriverManager.getConnection或OracleDataSource.setConnectionProperties的java.util.Properties對象來設置連接屬性。您可以通過在java命令行中包含-D選項來設置系統屬性。

java -Doracle.jdbc.V8Compatible =「true」MyApp Oracle JDBC 11.1修復了此問題。從此版本開始,驅動程序默認將SQL DATE列映射到java.sql.Timestamp。沒有必要設置V8Compatible來獲得正確的映射。 V8Compatible強烈棄用。你根本不應該使用它。如果你將它設置爲true,它不會傷害任何東西,但你應該停止使用它。

儘管很少用到這種方式,但V8Compatible並不修復DATE到日期問題,而是支持與8i數據庫的兼容性。 8i(和更舊的)數據庫不支持TIMESTAMP類型。設置V8Compatible不僅導致SQL DATE在從數據庫讀取時映射到時間戳,還導致所有時間戳在寫入數據庫時​​轉換爲SQL DATE。由於8i不受支持,因此11.1 JDBC驅動程序不支持此兼容模式。出於這個原因,V8Compatible是desupported。

如上所述,默認情況下,11.1版驅動程序在從數據庫讀取時將SQL DATE轉換爲時間戳。這總是正確的做法,9i的改變是一個錯誤。 11.1車手已恢復到正確的行爲。即使您沒有在應用程序中設置V8Compatible,在大多數情況下也不應該看到任何行爲差異。如果您使用getObject讀取DATE列,您可能會注意到不同之處。結果將是一個時間戳而不是日期。由於Timestamp是Date的一個子類,所以這通常不是問題。如果您依賴從DATE到Date的轉換來截斷時間組件,或者如果您對該值執行toString,您可能會注意到不同之處。否則,更改應該是透明的。

如果由於某種原因,您的應用程序對此更改非常敏感,並且您只需具有9i-10g行爲,則可以設置連接屬性。將mapDateToTimestamp設置爲false,驅動程序將恢復爲默認的9i-10g行爲並將DATE映射到日期。

如果可能,您應該將您的列類型更改爲TIMESTAMP而不是DATE。

- 理查德


羅傑·沃斯寫道: 我張貼以下的計算器問題/問題,因此,如果有人知道的決議,將是很好的看到它回答有:

的Oracle SQL DATE通過Java JDBC使用iBATIS

這裏轉換問題的問題描述:

我目前WRES使用Java的iBATIS處理Oracle SQL DATE轉換問題。

正在使用Oracle JDBC瘦驅動程序ojdbc14版本10.2.0.4.0。 iBATIS版本2.3.2。 Java 1.6.0_10-rc2-b32。

的問題圍繞着正在被這個片段的SQL返回的日期類型的列:

SELECT * FROM 表(pk_invoice_qry.get_contract_rate(,,,,,,??????? ,?,?,?))order by from_date

程序包過程調用返回一個正在包裝在TABLE中的遊標遊標,在那裏很容易讀取結果集,就像對錶進行select查詢一樣。

在PL/SQL開發人員,其中一列返回,FROM_DATE,SQL日期型,具有精度一天的時間:

Tue Dec 16 23:59:00 PST 2008 

但是當我通過iBATIS的和JDBC,值訪問此只當顯示像這樣

Tue Dec 16 12:00:00 AM PST 2008 

這是清晰的:保持精確到天

應該是:紀元以來的01 1229500740000毫秒週二,2008年12月16日,下午11點59分零零秒PST

但是,讓這個代替: 1229414400000毫秒紀元以來 週二,2008年12月16日12:00:00 AM PST (如Java的類實例。 sql.Date)

無論我嘗試什麼,我都無法公開此DATE列的完整精度以通過Java JDBC和iBATIS返回。

什麼iBATIS的是從映射是這樣的:

FROM_DATE:2008-12-03:類java.sql中。日期

當前iBATIS的映射是這樣的:

我也試過:

但是,所有試圖映射產生相同的截斷日期值。就好像JDBC在iBATIS甚至觸及它之前已經做了丟失數據精度的損害。

顯然,當我留在PL/SQL Developer中運行相同的SQL代碼段作爲測試腳本時,我沒有通過JDBC和iBATIS取消部分數據精度。根本不可接受,非常令人沮喪,並最終非常可怕。

+0

鏈接無法正常工作;( – 2013-06-27 09:10:52

0

問題是使用java.sql.Date。根據Javadoc,必須通過將實例關聯的特定時區中的小時,分​​鍾,秒和毫秒設置爲零來將「實例化」由「java.sql.Date」實例包裝的毫秒值「標準化」,以符合SQL的定義DATE

0

是的,我明白了 - 普通的SQL DATE標準必須只存儲到日分辨率。事實上,這裏是Oracle的DATE類型的代碼段:

Oracle支持日期和時間, 雖然不同於SQL2 標準。而不是使用兩個 獨立實體,日期和時間, Oracle僅使用一個DATE。日期 類型存儲在特殊的內部 格式中,該格式不僅包括月,日,年的 ,還包括小時,分鐘和秒的 。

這使得Oracle的DATE超過標準SQL DATE。

嗯,Oracle PL/SQL人員廣泛使用DATE來保存取決於第二個分辨率的值。看起來像iBATIS需要類似於Hibernate sql dialect概念,而不是通過java.sql.Date解釋DATE,而是可以覆蓋,而是通過java.util.Date解釋,而Javadocs將其定義爲允許毫秒分辨率。

不幸的是,當我已經改變了映射是這樣的:

<result property="from_date" jdbcType="DATE" javaType="java.util.Date"/> 

<result property="from_date" jdbcType="DATETIME" javaType="java.util.Date"/> 

它仍然看似第一翻譯SQL日期爲java.sql.Date,失去了時間日精度。

5

我發現瞭如何解決這個問題。 iBATIS允許自定義類型處理程序進行註冊。所以在我的SqlMap-config.xml文件中添加此:

<typeAlias alias="OracleDateHandler" type="com.tideworks.ms.CustomDateHandler"/> 
<typeHandler callback="OracleDateHandler" jdbcType="DATETIME" javaType="date"/> 

,然後加入這一類,它實現了iBATIS的TypeHandlerCallback接口:Whennever我需要映射的Oracle日期我現在形容

// corrected getResult()/setParameter() to correctly deal with when value is null 
public class CustomDateHandler implements TypeHandlerCallback { 
    @Override 
    public Object getResult(ResultGetter getter) throws SQLException { 
     final Object obj = getter.getTimestamp(); 
     return obj != null ? (Date) obj : null; 
    } 

    @Override 
    public void setParameter(ParameterSetter setter,Object value) throws SQLException { 
     setter.setTimestamp(value != null ? new Timestamp(((Date)value).getTime()) : null); 
    } 

    @Override 
    public Object valueOf(String datetime) { 
     return Timestamp.valueOf(datetime); 
    } 
} 

它像這樣:

<result property="from_date" jdbcType="DATETIME" javaType="date"/> 
+0

不錯,我不確定如何克服這個問題,但我很高興我能指出你在正確的方向 – ninesided 2008-12-24 00:48:37

+0

我看不到你的進口。當您將值轉換爲日期時,該util或sql? – bwfrieds 2017-01-26 21:39:37

2

我已經解決了使用jdbcType爲 「時間戳」,而不是jdbcType爲 「DATE」

•問題我的問題:

•解決:

問候。

Pedro

1

問題出在Oracle驅動程序。

我發現最好的解決辦法是改變所有jdbcType爲 「DATE」,以jdbcType爲 「時間戳」 和所有#column_name:DATE#至#column_name:TIMESTAMP#

因此改變:

<result property="from_date" jdbcType="DATE" javaType="java.sql.Date"/> 

<result property="from_date" jdbcType="TIMESTAMP" javaType="java.sql.Date"/> 
0

理查德·耶提到,甲骨文公司的最新驅動程序解決此問題。我可以證實這一點。在這裏與10.2驅動程序有同樣的問題,今天升級到ojdbc5.jar(11.2.0.1.0),現在問題已經消失。