【问题标题】:Failed to store java.time.ZonedDateTime using hibernate PostgreSQL使用休眠 PostgreSQL 存储 java.time.ZonedDateTime 失败
【发布时间】:2017-06-02 10:42:17
【问题描述】:

我有一个实体,它扩展了一个名为 AbstractAuditingEntity 的审计实体类,其中一个字段是

@CreatedDate
@Column(name = "created_date", nullable = false)
@JsonIgnore
private ZonedDateTime createdDate

以上字段映射到名为"created_date" 的数据库字段,类型为"timestamp without time zone"

但是在保存这个实体的时候,PostgresSQL 会抛出如下错误:

Caused by: org.postgresql.util.PSQLException: ERROR: column "created_date" is of type timestamp without time zone but expression is of type bytea
  Hint: You will need to rewrite or cast the expression.

我在这里寻找相同的错误并找到了解决方案:Postgresql UUID supported by Hibernate?

但是解决方案是针对java.util.UUID,在解决方案中建议在UUID类型的字段上添加注解@Type(type="pg-uuid")

有没有像 pg-uuid 这样的现成类型值用于 ZonedDateTime ? hibernate @Type 注释的不同值常量的任何参考链接?

或者应该写一个自定义的反序列化器类?如何编写这样的反序列化器类有参考链接?

PostgresSQL Version  : 9.6,
<liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>

【问题讨论】:

  • 您可以在您的记录器中启用org.hibernate.type 的调试日志吗?如果类型已注册 pastebin.com/t2xh5UvM 并且应该可以工作,您应该会找到类似的内容。
  • 在 Hibernate 5.2 之前,Java 8 时间类的处理来自一个可选模块。

标签: java spring postgresql hibernate


【解决方案1】:

对于 Hibernate 5.2,它应该开箱即用。

对于 5.0,您可以添加一个依赖项来支持它:

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

对于 4.3,您可以使用 JPA 2.1 转换器:

@Converter
public class TimestampConverter implements AttributeConverter<ZonedDateTime, Timestamp> {
    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime zonedTime) {
        if (zonedTime == null) {
            return null;
        }
        return new Timestamp(zonedTime.toInstant().toEpochMilli());
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp localTime) {
        if (localTime == null) {
            return null;
        }
        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(localTime.getTime()), ZoneId.systemDefault());
    }
}

然后用@Convert注释你的属性:

@Convert(converter = TimestampConverter.class)
private ZonedDateTime createdDate;

我注意到您的数据库列是TIMESTAMP。确实应该是TIMESTAMP WITH TIME ZONE,尤其是当您的客户时区有夏令时更改时。

【讨论】:

  • 请注意,您在 4.3 的解决方案中丢失了时区信息。
  • Postgres 不在TIMESTAMPTIMESTAMP WITH TIME ZONE 中存储偏移信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 2014-06-30
  • 2013-06-30
  • 1970-01-01
  • 2017-08-04
  • 2013-01-02
  • 2017-09-29
相关资源
最近更新 更多