JPA支持Java 8新的日期和时间API

时间:2014-05-18 03:50:39

标签: java jpa java-8 jpa-2.1 java-time

我正在将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实现。

8 个答案:

答案 0 :(得分:71)

对于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.2Integrate Hibernate 5.2 with Spring framework 4.x

答案 1 :(得分:19)

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

答案 2 :(得分:11)

JPA 2.2支持java.time

JPA 2.2 现在支持LocalDateLocalTimeLocalDateTimeOffsetTimeOffsetDateTime

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

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

Hibernate 5支持比JPA 2.2更多的java类型,如DurationInstantZonedDateTime

更多信息:

答案 3 :(得分:9)

我在我的项目中使用Java 8,EclipseLink(JPA 2.1),PostgreSQL 9.3和PostgreSQL驱动程序-Postgresql-9.2-1002.jdbc4.jar,我可以使用新API中的LocalDateTime变量,但数据类型没有问题列中的列是数据库中的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();
}

答案 4 :(得分:9)

org.jadira.usertype可用于保留JSR 310日期和时间API。

查看此example project

来自示例项目,

@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;
}

答案 5 :(得分: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进行了注释。

答案 6 :(得分: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();
    }

}

答案 7 :(得分:0)

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

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

这里我使用的是传统的纪元格式https://www.epochconverter.com/ epoch是非常灵活和可接受的格式

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

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

或使用临时的

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