58

我正在为我的新项目使用 Java 8。

我正在尝试在 java 8 中使用新的日期和时间 API,但是我不知道是否JPA 2.1完全支持这个新的日期和时间 API。

请分享您在 JPA 对 Java 8 中新的日期和时间 API 的支持方面的经验/意见。

我可以通过 JPA 2.1 在 Java 8 中安全地使用新的日期和时间 API 吗?

更新:

我使用 Hibernate (4.3.5.Final) 作为 JPA 实现。

4

8 回答 8

73

对于 Hibernate 5.X,只需添加

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-java8</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

@NotNull
@Column(name = "date_time", nullable = false)
protected LocalDateTime dateTime;

无需任何额外努力即可工作。见https://hibernate.atlassian.net/browse/HHH-8844

更新:

请看一下 Jeff Morin 的评论:从 Hibernate 5.2.x 开始就足够了

 <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-core</artifactId>
     <version>5.2.1.Final</version>
 </dependency>
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-...</artifactId>
     <version>4.3.1.RELEASE</version>
 </dependency>

请参阅https://github.com/hibernate/hibernate-orm/wiki/Migration-Guide---5.2并将 Hibernate 5.2 与 Spring 框架 4.x 集成

于 2015-10-07T20:26:38.970 回答
21

JPA 2.1 是在 Java 1.8 之前出现的规范,因此不要求对其提供任何支持。显然,一些实现可能支持一些 Java 1.8 特性。有些Java 1.8 字节码有问题(例如EclipseLink)。我知道 DataNucleus 支持 java.time 和 Java 1.8,因为那是我使用的。您必须检查您的实现以了解其支持级别。

已要求 JPA 2.2 支持 java.time 类型,请参阅此问题https://java.net/jira/browse/JPA_SPEC-63

于 2014-05-18T04:08:44.653 回答
11

JPA 2.2 支持 java.time

JPA 2.2现在支持LocalDateLocalTimeLocalDateTime和.OffsetTimeOffsetDateTime

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>javax.persistence-api</artifactId>
  <version>2.2</version>
</dependency>

对于 JPA 2.2 实现,可以使用Hibernate 5.2EclipseLink 2.7 。

Hibernate 5 支持比 JPA 2.2 更多的 java 类型,如Duration,InstantZonedDateTime.

更多信息:

于 2017-09-04T14:31:17.810 回答
9

我在我的项目中使用 Java 8、EclipseLink(JPA 2.1)、PostgreSQL 9.3 和 PostgreSQL Driver -Postgresql-9.2-1002.jdbc4.jar,我可以使用LocalDateTime新 API 中的变量而没有错误,但列的数据类型将是数据库中的 bytea。据我所知,您只能从 Java 应用程序中读取它。

但是,您可以使用AttributeConverter将这些类转换为java.sql.Date. 我从Java.net找到了这段代码

@Converter(autoApply = true)
public class LocalDatePersistenceConverter implements
AttributeConverter {
@Override
public java.sql.Date convertToDatabaseColumn(LocalDate entityValue) {
    return java.sql.Date.valueOf(entityValue);
}

@Override
public LocalDate convertToEntityAttribute(java.sql.Date databaseValue) {
    return databaseValue.toLocalDate();
}
于 2014-07-03T21:58:51.230 回答
9

org.jadira.usertype可用于持久化 JSR 310 日期和时间 API。

查看这个示例项目

从示例项目,

@MappedSuperclass
public class AbstractEntity {

    @Id @GeneratedValue Long id;

    @CreatedDate//
    @Type(type = "org.jadira.usertype.dateandtime.threeten.PersistentZonedDateTime")//
    ZonedDateTime createdDate;

    @LastModifiedDate//
    @Type(type = "org.jadira.usertype.dateandtime.threeten.PersistentZonedDateTime")//
    ZonedDateTime modifiedDate;
}
于 2014-10-10T04:11:40.343 回答
3

我知道这是一个老问题,但我想到了一个可能有用的替代解决方案。

您可以利用@Transient,而不是尝试将新的 java.time.* 类映射到现有的数据库类型:

@Entity
public class Person {
    private Long id;        
    private Timestamp createdTimestamp;

    @Id
    @GeneratedValue
    public Long getId() { return id; }

    private Timestamp getCreatedTimestamp() {
        return createdTime;
    }

    private void setCreatedTimestamp(final Timestamp ts) {
        this.createdTimestamp = ts;
    }

    @Transient
    public LocalDateTime getCreatedDateTime() {
        return createdTime.getLocalDateTime();
    }

    public void setCreatedDateTime(final LocalDateTime dt) {
        this.createdTime = Timestamp.valueOf(dt);
    }
}

您使用使用新的 Java 8 日期/时间类的公共 getter/setter 方法,但在幕后,getter/setter 使用旧的日期/时间类。当您持久化实体时,将保留旧的日期/时间属性,但不会保留新的 Java 8 属性,因为它使用 @Transient 进行了注释。

于 2014-12-14T19:26:01.297 回答
1

对于TIMESTAMP类型,您可以使用此转换器:

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime datetime) {
        return datetime == null ? null : Timestamp.valueOf(datetime);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
        return timestamp == null ? null : timestamp.toLocalDateTime();
    }

}

对于DATE类型,您可以使用此转换器:

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate date) {
        return date == null ? null : Date.valueOf(date);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return date == null ? null : date.toLocalDate();
    }

}

对于TIME类型,您可以使用此转换器:

@Converter(autoApply = true)
public class LocalTimeAttributeConverter implements AttributeConverter<LocalTime, Time> {

    @Override
    public Time convertToDatabaseColumn(LocalTime time) {
        return time == null ? null : Time.valueOf(time);
    }

    @Override
    public LocalTime convertToEntityAttribute(Time time) {
        return time == null ? null : time.toLocalTime();
    }

}
于 2017-10-10T16:59:30.590 回答
0

有很多方法可以做,这也取决于你的框架:如果你的框架在现场转换器上有这样的弹簧,请这样做:1-

@DateTimeFormat(pattern = "dd.MM.yyyy - HH:mm")
private Long createdDate;

在这里,我使用的是旧版 epoch 格式https://www.epochconverter.com/ epoch 是非常灵活且可以接受的格式

2-其他方法是使用 jpa @PostLoad @PreUpdate @PrePersist

@PostLoad
      public void convert() {
        this.jva8Date= LocalDate.now().plusDays(1);
      }

或使用 temp 之一

@Transient
public LocalDateTime getCreatedDateTime() {
    return createdTime.getLocalDateTime();
}
于 2017-08-27T10:15:48.880 回答