最近工做中用到了这三种数据库对日期字段的操做,现作以下总结。java
1.数据库字段与java类型的对应关系。mysql
明白这对应关系,咱们才能正确的使用PreparedStatement设置参数sql
2.关于日期字段的几点说明数据库
首先任何的日期字段设置的时候都应尽可能保持类型对应设置。oracle
好比:oracle的date字段,若是你想保留年月日时分秒,那么就应该用函数
setTime(java.sql.Time)或者setTimestamp(java.sql.Timestamp)来设置值,这两个仍是有区别的尽管执行结果会同样sqlserver
再好比:若是是mysql的time字段设置值那么应该是spa
setTime(java.sql.Time)code
虽然,其余的设置也能够执行成功,注意这里说的是成功,并非说合理orm
好比:若是是mysql的time字段设置值,你经过
setTimestamp(java.sql.Timestamp)设置值,那么其实到数据库里只会用到时分秒字段。这中方式还能够理解,并且还算合理(由于毕竟有时分秒而且这个时分秒是有效的)
若是经过setDate(java.sql.Date)来设置值,那么问题就大了,由于你设置了java.sql.Date,而这么设置,数据库只会拿到时分秒,而这个Date类型是没有时分秒的,也就是说我取时分秒字段,而你没有时分秒字段,那还了得,确定不合理。
因此,为啥说,不一样的数据库,必定要根据不一样数据库的不一样字段对应的字段关系来合理使用setDate,setTime,setTimestamp方法,请参照第一点说的
3.oracle的日期字段,这个至关特别
从第一点java与数据库的对应关系上看,发现一个难以想象的问题。那就是java.sql.Time对应了oracle中的date类型。别人都是java.sql.Timestamp类型对应日期字段(包含年月日时分秒的),并且别人java.sql.Time对应的都是时分秒字段(没有年月日)
咱们都知道oracle的date类型包含了年月日时分秒(固然也能够存储没有时分秒的),而java.sql.Time只是存储了时间信息(至少对于mysql,sqlserver都是这么用的,只用到了时分秒。但实际上java.sql.Time可定会存储年月日信息,不然oracle怎么能准确获取到年月日信息)
没错,oracle经过setTime字段设置的参数,到数据库中仍然会准确的保存到年月日信息(前提是你的数据库字段得是date或者timestamp类型)
你觉得这么就完了吗?
错,oracle还有个使人恶心的,你说你java.sql.Time对应数据的date字段就对应吧,获取的时候若是经过getTime()获取日期date字段,那么恭喜你你上当了,获取到的日期变成了1970-01-01 xx:xx:xx 时分秒是对的,可是日期是什么啊。
正确的获取方式是经过getTimestamp()方法来获取
举个oracle的例子,t_1表中有四个字段
id number类型
tdate1 date类型
tdate2 timestamp类型
tdate3 date类型
注意记录的样子,
tdate1我是经过setDate(java.sql.Date)设置的
tdate2我是经过setTimestamp(java.sql.Timestamp)设置的
tdate3我是经过setTime(java.sql.Time)设置的(固然也能够经过setTimestamp(java.sql.Timestamp)设置值)
可是查询这条记录的时候:
tdate1字段值的获取经过getDate()
tdate2字段值的获取经过getTimestamp()
tdate3字段值的获取经过getTimestamp(),注意这里千万不能使用getTime()获取
3.说一说oracle中,setTimestamp和setTime的区别(mysql,sqlserver没有这种区别,由于他们的java.sql.Time不会对应日期字段(包含年月日时分秒的日期字段))
要说区别,对于结果可能没什么区别或者说区别不大(不管是更新仍是插入,结果都是同样的,都年月日时分秒),可是执行效率确实不同的,怎样肯定执行效率,那就须要查询oracle的执行计划才能明白。
实验:仍是第二点的表,咱们如今更新一下id字段,where条件是tdate3=?
String sql="update t_1 set id=12 where tdate3=?"; PreparedStatement ps= conn.prepareStatement(sql); java.util.Date d=new java.util.Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-07-23 21:31:19").getTime()); ps.setTimestamp(1, new Timestamp(d.getTime())); System.out.println(ps.executeUpdate());
查看该条语句执行计划:查看方法不在这里提了
关键点在于filter(INTERNAL_FUNCTION("TDATA3")),这句话的意思是内部函数进行了类型转换,而后匹配传过来的参数,注意这里转换的是字段,而不是传过来的值。
一样,咱们经过setTime试试
String sql="update t_1 set id=13 where tdate3=?"; System.out.println(conn); PreparedStatement ps= conn.prepareStatement(sql); java.util.Date d=new java.util.Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-07-23 21:31:19").getTime()); ps.setTime(1, new Time(d.getTime())); System.out.println(ps.executeUpdate());
查询执行计划:filter("TDATE3"),也就是说没有进行任何的类型转换,直接赋值了
再来讲说,类型转换与不转换的区别。
类型转换,oracle会调用内部的函数对字段进行转换,而后匹配,这种访问速度确定没有不进行任何类型转换的速度快,这就涉及到了执行效率问题。
特别注意,若是时间字段是索引字段,那么这两种访问速度差距会很大。
一样,也能够进行试验。
那就是将tdate3字段做为主键,id做为普通字段。
而后执行上述试验过程,会发现:
经过setTimestamp设置的参数,走的是全表扫描 TABLE ACCESS FULL|
而经过setTime设置的参数,走的是INDEX UNIQUE SCAN 惟一键索引,这速度确定要比全表扫描快得多。
4.mysql,sqlserver说明
mysql,sqlserver没有oracle这种变态的问题
对应什么类型就是什么类型,setTimestamp设置的参数,就经过getTimestamp获取,
setDate设置的参数就经过getDate获取,setTime设置的参数,就经过getTime获取
5.总结
不一样字段的类型参数设置必定要按照对应的java类型来设置参数,尽管不一样的类型也可能设置成功,可是大部分都是不合理的,或者说即使是合理的,执行效率也会有必定的影响。尤其注意的是oracle
设置的时候setTime(java.sql.Time)设置参数,getTimestamp取得字段值。