Posted on 2008-03-26 17:17
bluoy 閱讀(1791)
評論(0) 編輯 收藏
項目中組員偶然寫了一段垃圾的sql語句,不想?yún)s誤打誤撞的發(fā)現(xiàn)了一個jdbc的bug,包括Oracle 10g附帶的版本。
詳細(xì)描述可以參考如下代碼:
public static void testSetTimestampBug() throws Exception{
Calendar calendar = new GregorianCalendar();
Date d = calendar.getTime();
String sql = "select 1+1 from dual where ?-sysdate<1"; //error sql
String sql1 = "select ?-sysdate from dual"; //no error sql
String sql2 = "select 1+1 from dual where ?-1<sysdate"; //no error sql
PreparedStatement pst = cn.prepareStatement(sql);
//pst.setDate(1, new java.sql.Date(d.getTime())); //no error
pst.setTimestamp(1, new java.sql.Timestamp(d.getTime())); //bug!!!, throw SQLException: ORA-00932
}
三種sql的寫法中,第一種寫法在使用setTimestamp()時會出錯,其他倆種卻不會有問題。
即正常調(diào)用PreparedStatement.setTimestamp()方法,遇到某些特殊寫法的sql語句卻會出錯。
本例中,拋出如下例外:
java.sql.SQLException: ORA-00932: inconsistent datatypes: expected NUMBER got INTERVAL.
然而,如果使用setDate()方法,則一切正常,三種寫法都沒有問題。
因?yàn)橛羞@個問題,如果在持久層使用了其他的中間件,則這個問題可能變的更加隱蔽,比如iBatis中的處理是這樣的:
java.util.Date --->
ibatis.DateTypeHandler----->PreparedStatement.setTimestamp()
java.sql.Date
---> ibatis.SqlDateTypeHandler----->PreparedStatement.setDate()
如果不注意輸入?yún)?shù)類型的話,就會遇到上述問題。我就因此費(fèi)了不少周折。
對于iBatis的使用建議,保證入口參數(shù)類型始終為java.sql.Date即可。