代码之家  ›  专栏  ›  技术社区  ›  chepseskaf Nick Holt

如何在JPA中使用java.sql.Timestamp作为真正的java.util.Date

  •  14
  • chepseskaf Nick Holt  · 技术社区  · 14 年前

    我对毫秒日期的管理有问题。我知道需要使用时间戳来存储毫秒:

    @Temporal(TIMESTAMP)
    @Column(name="DATE_COLUMN", nullable = false)
    @Override public java.util.Date getDate() { return this.date; }
    

    this.date 实例是java.sql.Timestamp。如何从JPA获取java.util.Date?因为来自JPA的日期,即使方法签名是java.util.date,实际上也是java.sql.Timestamp的一个实例。

    java.util.Date newDate = new Date(this.date.getTime());
    this.date.equals(newDate) == false
    newDate.equals(this.date) == true
    

    @Override
    public Date getDate() {
      return this.date == null ? null : new Date(this.date.getTime());
    }
    

    它是有效的,但是在有大量数据的情况下效率不高。

    • 我可以使用 @PostLoad 为了在我检索到一个java.util.Date之后,从该日期开始创建一个java.util.Date。

    • 我想知道我是否不能用 ClassTransformer

    你遇到过这个问题吗?我不正确的地方是什么?处理这个问题的最好方法是什么?

    5 回复  |  直到 14 年前
        1
  •  7
  •   Bozho    14 年前

    java.sql.Timestamp 覆盖 compareTo(Date) 方法,所以使用 compareTo(..)

    java.util.Date

    此外,您可以随时比较 date.getTime() ,而不是对象本身。

    更进一步-你可以使用 long 存储日期的字段。甚至是 DateTime

        2
  •  12
  •   Pascal Thivent    14 年前

    TBH,我不确定它的确切状态,但Hibernate的方式可能确实有问题(哪个是您的JPA提供者,对吧?)手柄 TIMESTAMP 柱。

    映射SQL 时间戳 给一个 java.util.Date ,Hibernate使用 TimestampType 它实际上会分配一个 java.sql.Timestamp 日期类型 Timestamp.equals(Object) 非对称 Date.equals(Object) .

    因此,你不能“盲目”使用 myDate.equals(someRealJavaUtilDate) myDate 映射到SQL 时间戳 ,这当然不是真正可以接受的。

    this thread this one (阅读所有页面),Hibernate的用户和开发人员似乎从未就这个问题达成一致(参见 HB-681 )我只是不明白为什么。

    也许只是我,也许我只是错过了一些对别人来说很简单的事情,但问题在我看来是显而易见的,尽管我认为这很愚蠢 作为罪魁祸首,我仍然认为Hibernate应该保护用户不受此问题的影响。我不明白加文为什么不同意。

    同时,您可以使用自定义类型自己“修复”问题,方法如下(取自论坛并按原样粘贴):

    public class TimeMillisType extends org.hibernate.type.TimestampType {
    
        public Date get(ResultSet rs, String name) throws SQLException {
            Timestamp timestamp = rs.getTimestamp(name);
            if (timestamp == null) return null;
            return
                new Date(timestamp.getTime()+timestamp.getNanos()/1000000);
       }
    
    }
    
        3
  •  4
  •   Knubo    14 年前

    如果它与返回新java.util.Date的重写一起工作,那么使用该重写。或者更棒的是,去找乔达蒂姆。你会在网上找到很多这样做的例子。我不担心这里的性能,因为您的数据库比创建新的java.util.Date对象要慢得多。

    我看到你在用Hibernate。如果使用注释,可以执行以下操作:

    @Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
    public DateTime getProvisionByTime() {
        return provisionByTime;
    }
    

    然后,您将在持久化对象中从Jodatime获得很好的DateTime对象。如果您只想有一个日期,可以使用如下LocalDate:

    @Type(type = "org.joda.time.contrib.hibernate.PersistentLocalDate")
    public LocalDate getCloudExpireDate() {
        return cloudExpireDate;
    }
    

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.2.6.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.3.1.GA</version>
        </dependency>
    
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time-hibernate</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
                <version>1.6.1</version>
        </dependency>
    
        4
  •  2
  •   Lokesh Mehra Endkill    12 年前

    这个问题对于DAO测试来说非常关键:

    Employer employer1 = new Employer();
    employer1.setName("namenamenamenamenamename");
    employer1.setRegistered(new Date(1111111111)); // <- Date field
    
    entityManager.persist(employer1);
    assertNotNull(employer1.getId());
    
    entityManager.flush();
    entityManager.clear();
    
    Employer employer2 = entityManager.find(Employer.class, employer1.getId());
    assertNotNull(employer2);
    assertEquals(employer1, employer2); // <- works
    assertEquals(employer2, employer1); // <- fails !!!
    

    所以结果真的很令人惊讶,编写测试变得很棘手。

    但是在实际的业务逻辑中,您永远不会使用实体作为集合/映射键,因为它是巨大的,而且是可变的。你永远不会用 equal 比较。同时,也应避免对整个实体进行比较。

    通常的场景使用不可变的实体ID作为映射/设置键,并将时间值与 compareTo() 方法或只是使用 getTime() 价值观。

    http://pastebin.com/7TgtEd3x

    http://pastebin.com/DMrxzUEV

    我已经改写了我使用的方言:

    package xxx;
    
    import org.hibernate.dialect.HSQLDialect;
    import org.hibernate.type.AdaptedImmutableType;
    import xxx.DateTimestampType;
    
    import java.util.Date;
    
    public class CustomHSQLDialect extends HSQLDialect {
    
        public CustomHSQLDialect() {
            addTypeOverride(DateTimestampType.INSTANCE);
            addTypeOverride(new AdaptedImmutableType<Date>(DateTimestampType.INSTANCE));
        }
    }
    

    我还没有决定-我是将这种方法用于测试和生产,还是仅用于测试。

        5
  •  1
  •   James    14 年前

    你在使用什么JPA提供者?你在EclipseLink,JPA参考实现中试过这个吗?