Posted on 2008-03-26 17:17
bluoy 阅读(1781)
评论(0) 编辑 收藏
项目中组员偶然写了一段垃圾的sql语句,不想却误打误撞的发现了一个jdbc的bug,包括Oracle 10g附带的版本。
详细描述可以参考如下代码:
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()时会出错,其他俩种却不会有问题。
即正常调用PreparedStatement.setTimestamp()方法,遇到某些特殊写法的sql语句却会出错。
本例中,抛出如下例外:
java.sql.SQLException: ORA-00932: inconsistent datatypes: expected NUMBER got INTERVAL.
然而,如果使用setDate()方法,则一切正常,三种写法都没有问题。
因为有这个问题,如果在持久层使用了其他的中间件,则这个问题可能变的更加隐蔽,比如iBatis中的处理是这样的:
java.util.Date --->
ibatis.DateTypeHandler----->PreparedStatement.setTimestamp()
java.sql.Date
---> ibatis.SqlDateTypeHandler----->PreparedStatement.setDate()
如果不注意输入参数类型的话,就会遇到上述问题。我就因此费了不少周折。
对于iBatis的使用建议,保证入口参数类型始终为java.sql.Date即可。