java.util.Date vs java.sql.Date

java.util.Date vs java.sql.Date :何时使用哪个和为什么?

恭喜,你已经用JDBC打了我最喜欢的宠物:date类处理。

基本上数据库通常至less支持三种forms的date时间字段,即date,时间和时间戳。 它们中的每一个在JDBC中都有相应的类,并且每个都扩展了java.util.Date 。 这三者中每一个的快速语义如下:

  • java.sql.Date对应于SQL DATE,这意味着它存储年,月和日,小时,分钟,秒和毫秒被忽略。 另外sql.Date不绑定到时区。
  • java.sql.Time对应于SQL TIME,应该很明显,只包含有关小时,分钟,秒和毫秒的信息
  • java.sql.Timestamp对应于SQL TIMESTAMP,它的确切date为纳秒( 注意util.Date仅支持毫秒! ),具有可自定义的精度。

使用与这三种types相关的JDBC驱动程序时最常见的错误之一是types处理不正确。 这意味着sql.Date是特定sql.Date时区的, sql.Time包含当前的年,月,日等等。

最后:哪一个使用?

取决于字段的SQLtypes,真的。 PreparedStatement具有所有三个值的setter,其中#setDate()sql.Date#setTime()sql.Time#setTimestamp()sql.Timestamp

请注意,如果你使用ps.setObject(fieldIndex, utilDateObject); 实际上你可以给大多数JDBC驱动程序提供一个正常的util.Date ,它可以很好地吞噬它,就好像它是正确的types,但是当你以后请求数据的时候,你可能会注意到你实际上错过了一些东西。

我真的是说根本不应该使用date。

我的意思是把毫秒/毫微秒保存为简单的长整数,然后将它们转换成你正在使用的任何对象( 强制性的joda-time插件 )。 一种可以做的方法是将date组件作为一个长时间组件存储为另一个,例如现在将是20100221和154536123.这些神奇数字可以在SQL查询中使用,并且可以从数据库移植到另一个,将让你完全避免这个部分的JDBC / Java Date API:s。

LATE EDIT:从Java 8开始,如果你完全可以避免使用java.util.Datejava.sql.Date ,而不是使用java.time包(基于Joda)而不是其他任何东西。 如果你不在Java 8上,这里是原始的回应:


java.sql.Date – 当您调用使用它的库的方法/构造函数(如JDBC)时。 否则。 您不想为不明确处理JDBC的应用程序/模块引入依赖关系到数据库库。

java.util.Date – 使用库时使用它。 否则,尽可能less的原因有几个:

  • 这是可变的,这意味着每次将它传递给方法或从方法返回时,都必须作出防御副本。

  • 它不能很好地处理date,像你这样倒退的人真的认为date处理类应该。

  • 现在,因为juD不擅长工作,所以引入了可怕的Calendar类。 他们也是可变的,可怕的工作,应该避免,如果你没有任何select。

  • 还有更好的select,比如Joda Time API ( 甚至可以把它变成Java 7,成为新的官方date处理API– 快速search不会)。

如果你觉得引入像Joda这样的新依赖是过时的,那么对于时间戳字段来说, long对于对象中的时间戳字段来说并不是那么糟糕,尽pipe我自己通常会把它们包装在juD中,为了types安全和文档。

使用java.sql.Date的唯一时间是在PreparedStatement.setDate 。 否则,使用java.util.Date 。 它告诉ResultSet.getDate返回一个java.sql.Date但它可以直接分配给一个java.util.Date

我有同样的问题,我发现插入当前date到一个准备好的声明最简单的方法是这样的:

 preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime())); 

Java中的java.util.Date类表示特定的时刻(例如,2013年11月25日16:30:45到毫秒),但DB中的DATE数据types仅表示date(例如, 2013年11月25日)。 为了防止您错误地向数据库提供java.util.Date对象,Java不允许直接将SQL参数设置为java.util.Date:

 PreparedStatement st = ... java.util.Date d = ... st.setDate(1, d); //will not work 

但它仍然允许你通过强制/意图来做到这一点(然后数据库驱动程序将忽略小时和分钟)。 这是用java.sql.Date类完成的:

 PreparedStatement st = ... java.util.Date d = ... st.setDate(1, new java.sql.Date(d.getTime())); //will work 

一个java.sql.Date对象可以存储一个时间片段(这样可以很容易地从java.util.Date中构造出来),但是如果你试图问几个小时的时候会抛出一个exception(为了强化它的一个概念仅限date)。 数据库驱动程序预计会识别这个类,并只使用0的时间。 尝试这个:

 public static void main(String[] args) { java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight java.sql.Date d2 = new java.sql.Date(12345); System.out.println(d1.getHours()); System.out.println(d2.getHours()); }