Oracle getTime()保持毫秒

时间:2017-02-21 11:00:33

标签: java oracle hibernate date jdbc

我们有一个Spring + Hibernate Java 7 Web应用程序。我们目前使用.hbm.xml Hibernate文件(而不是更常见的已知注释)作为Java实体和数据库表之间的映射。

我们的一个Java实体类具有精度为毫秒的java.util.Date

public class SomeEntity extends AbstractEntity{
   ...

   private java.util.Date someDate; // with ms precision

   ...
}

在我们的.hbm.xml文件中,我们有以下日期:

...
<hibernate-mapping>
  <class name="com.namespace.Entity" table="entity" batch-size="10">
     ...
     <property name="SomeDate" column="somedate" type="com.namespace.CustomDateType" />
     ...

链接到具有以下行的数据库表:

SOMEDATE  TIMESTAMP(2)  NULLABLE=Yes

我们的CustomDateType班级:

package com.namespace.type;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;

import org.hibernate.usertype.UserType;

public class CustomDateType implements UserType {

  private static final int[] SQL_TYPES = { Types.TIMESTAMP };

  @Override
  public Object assemble(final Serializable serializable, final Object o) {
    return deepCopy(serializable);
  }

  @Override
  public Object deepCopy(final Object value) {
    return value;
  }

  @Override
  public Serializable disassemble(final Object o) {
    return (Serializable) deepCopy(o);
  }

  @Override
  public boolean equals(final Object x, final Object y) {
    if (x == y) {
      return true;
    } else if ((x == null) || (y == null)) {
      return false;
    }
    return x.equals(y);
  }

  @Override
  public int hashCode(final Object o) {
    return ((CustomDateType) o).hashCode();
  }

  @Override
  public boolean isMutable() {
    return false;
  }

  @Override
  public Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object owner) throws SQLException {
    Date result = null;
    final Timestamp timestamp = resultSet.getTimestamp(names[0]); // This is where the problem is
    if (!resultSet.wasNull()) {
      result = new Date(timestamp.getTime());
    }
    return result;
  }

  @Override
  public void nullSafeSet(final PreparedStatement statement, final Object value, final int index) throws SQLException {
    final Date dateToSet = (Date) value;
    statement.setTimestamp(index, dateToSet == null ? null : new Timestamp(dateToSet.getTime()));
  }

  @Override
  public Object replace(final Object o, final Object o1, final Object o2) {
    return o;
  }

  @Override
  public Class<Date> returnedClass() {
    return Date.class;
  }

  @Override
  public int[] sqlTypes() {
    return SQL_TYPES;
  }
}

当调试someDate确实在Java类中有毫秒时。但是,在CustomDateType#nullSafeGet方法中,生成的TimeStamp不再有任何毫秒。

resultSet参数是oracle.jdbc.driver.ForwardOnlyResultSet,它继续进入oracle.jdbc.driver.T4CPreparedStatement,继续进入班级&amp;方法的核心是:oracle.jdbc.driver.DateTimeCommonAccessor#getTime(int, Calendar)

在此方法中,milliseconds被剥离,您将获得second - 精度。

有没有办法在这种情况下保持毫秒?从java.util.Date到数据库TIMESTAMP - 类型列时,如何节省毫秒精度?

注意:进入数据库表之前,毫秒数已经消失。如果我在final Timestamp timestamp = resultSet.getTimestamp(names[0]);放置一个断点并跳过,结果timestamp将不再有毫秒。

编辑:调试期间hava.util.Date对象和java.sql.Timestamp对象的内容:

enter image description here enter image description here

fractionmillis都被删除并存入0 ..

1 个答案:

答案 0 :(得分:2)

java.sql.Timestampjava.util.Date fastTime字段中存储第二个精度(而不是普通java.util.Date的毫秒数),它有一个单独的nanos字段亚秒级精度。当你调用java.sql.Timestamp.getTime()时,它会将这两个重新组合成一个毫秒精度值。

由于您已声明您的字段为TIMESTAMP(2),这意味着您只有2位小数的亚秒精度。如果您尝试存储00:00:00.001,实际存储的内容为00:00:00:00,这也是您再次检索的内容。换句话说,您需要通过将字段声明为TIMESTAMP(3)(或者甚至更高,最多支持9)来提高精度,或者您需要使用两位小数的精度降低。

请注意,如果使用高于毫秒的精度(超过3位小数),则只能使用java.sql.Timestamp.getNanos()获得完全精度,其中包含完整的亚秒精度(nanos只是次要分数,应始终小于1秒),或将Timestamp转换为java.time.LocalDateTime