提问者:小点点

如何处理从Spring boot 1.4迁移到2.0.0时存储为byteArray的LocalDateTime


我正在将我的应用程序从Spring Boot 1.4. x和Spring Data 1.10.2迁移到Spring Boot 2.0.0和Spring Data 2.0.4

我遇到的最新问题似乎是Hibernate版本的变化。我有LocalDateTime/LocalDate,它们作为blob字节数组存储在DB中。它们看起来像\xaced00057372000d6a6176612e746……当我使用升级的依赖项启动应用程序时。我得到时间戳上的尾随垃圾:类型时间戳/日期/时间的错误值:{1}

我相信Hibernate现在看起来将LocalDateTime/LocalDate本机视为时间戳。以及来自先前实现的blob条目(不使用转换器)。导致这个问题。

你觉得怎么处理这件事?

一个实体可能有以下内容,对于排序很重要的日期,我们确实使用了转换器:

....

@Column("CREATE_DATE")
private LocalDate dateCreated;

@Column("TIME_STAMP_UPDATED")
@Convert(converter = MyLocalDateTimeConverter.class)
private LocalDateTime timestampUpdate;

....

共1个答案

匿名用户

我已经通过编写一个转换器解决了这个问题。值得注意的是,最初在HibernateORM中构建LDT到Blob转换器的团队并不期望人们使用它,而是包括Java8转换器或应用他们自己的转换器,就像我在上面所做的那样,我们需要更多的精度。

我想在DB中保留date作为TIMESTAMP或其他更实用的类型是有意义的,但同时我觉得如果我们构建某个东西,我们应该期望它以这种方式使用。尽管如此,这是我解决它的方法。

我收集了两个可用的解决方案。

>

  • 是更新我们的模式,将所有这些blob转换为TIMESTAMP并删除DB上的旧列。不是一个漂亮的解决方案。

    创建一个Mapper来强制ORM正确处理实体字段。使用Spring,这是非常简单的事情,我正在使用的解决方案取得了成功。如果你在我的代码中看到一些可以改进的东西,请评论!我想确保我正在实施和分享最好的解决方案。

    我创建了一个新类。

    import lombok.SneakyThrows;
    import lombok.extern.log4j.Log4j2;
    import org.apache.commons.lang3.ArrayUtils;
    
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.time.LocalDateTime; 
    ... 
    @Converter
    @Log4j2
    public class LegacyLocalDateTimeConverter implements AttributeConverter<LocalDateTime, Byte[]> {
    
        @SneakyThrows
        @Override
        public Byte[] convertToDatabaseColumn(final LocalDateTime localDateTime) {
            if(localDateTime == null) {
                return null;
            }
            try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                final ObjectOutputStream oos = new ObjectOutputStream(buffer)) {
                oos.writeObject(localDateTime);
                return ArrayUtils.toObject(buffer.toByteArray());
            }catch (Exception e){
                log.error("Error occurred converting ldt to byte[], e.message: [{}], e.cause: [{}], e.stack: [{}], e" +
                                ".class: [{}]",
                        e.getMessage(), e.getCause(), e.getStackTrace(), e.getClass());
                throw e;
            }
        }
    
        @SneakyThrows
        @Override
        public LocalDateTime convertToEntityAttribute(final Byte[] bytes) {
            if(bytes == null) {
                return null;
            }
            try(final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(ArrayUtils.toPrimitive(bytes));
                final ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)){
                final LocalDateTime dateTime = LocalDateTime.parse(objectInputStream.readObject().toString());
                log.info("Object: [{}]", dateTime);
                return  dateTime;
            }catch (Exception e){
                log.error("Error occurred converting byte[] to ldt, e.message: [{}], e.cause: [{}], e.stack: [{}], e" +
                                ".class: [{}]",
                        e.getMessage(), e.getCause(), e.getStackTrace(), e.getClass());
                throw e;
            }
    
        }
    }
    

    然后,我的问题中第一个代码块中的示例变为:

    ....
    
    @Column("CREATE_DATE")
    @Convert(converter = LegacyLocalDateTimeConverter.class)
    private LocalDate dateCreated;
    
    @Column("TIME_STAMP_UPDATED")
    private LocalDateTime timestampUpdate;
    
    .... 
    

    您会注意到我从timeStampUpdate中删除了转换器,并将我们的新转换器应用于dateCreated。Spring boot 2.0.0和Spring Data 2.0.4不再需要我们原来的转换器,因为它现在原生处理这个问题。在我的例子中,新的转换器(用H2和Postgres测试)处理存储在DB中的blob/byteArray对象,并且不再抛出有问题的错误。