Spring Boot 当Sping Boot (3.2)和Hibernate(6.4.0.Final)升级时,postgres中存储的大小增加

fsi0uk1n  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(70)

小故事

获取错误java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class [Ljava.lang.Object; (java.time.LocalDateTime and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')

说来话长

我正在将Sping Boot 从2.7.x升级到3.2。我已经通过在线搜索进行了升级。但是我对下面的实体字段之一进行了更改,因为我的应用程序没有启动。

// old
@Column(name = "last_modified")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime lastModified;

// new
@Column(name = "last_modified")
@JdbcType(BinaryJdbcType.class)
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime lastModified;

字符串
以前存储在Postgres中的数据的last_modified列大小为51字节,但在此更改后,新行的大小为430字节。
使用下面的转换器。这里的大小是51字节之前,放入数据库和也走出数据库。但旧的数据是造成问题。

@Override
public Byte[] convertToDatabaseColumn(final LocalDateTime localDateTime) {
    log.info("Inside convertToDatabaseColumn");
    if (localDateTime == null) {
        return null;
    }
    try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            final ObjectOutputStream oos = new ObjectOutputStream(buffer)) {
        oos.writeObject(localDateTime);
        log.info("buffer size: {}", buffer.size());
        return ArrayUtils.toObject(buffer.toByteArray());
    } catch (Exception e) {
        lalalalala
    }
}

@Override
public LocalDateTime convertToEntityAttribute(final Byte[] bytes) {
    // this line not executed in case of old data & works fine wit old data & gives 51 bytes
    log.info("Inside convertToEntityAttribute: {}", Array.getLength(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());
        return dateTime;
    } catch (Exception e) {
        lalalal
    }
}

其他尝试的解决方案

第一次

如果我不添加这个JdbcType注解,它将无法启动并给出错误Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Unable to determine SQL type name for column 'last_modified' of table 'resource': class org.hibernate.type.internal.CustomMutabilityConvertedBasicTypeImpl cannot be cast to class org.hibernate.type.BasicPluralType (org.hibernate.type.internal.CustomMutabilityConvertedBasicTypeImpl and org.hibernate.type.BasicPluralType are in unnamed module of loader org.springframework.boot.loader.launch.LaunchedClassLoader @37a71e93)"

2

我也在一些地方找到了下面的答案,但它在运行时会出错。

@Column(name = "last_modified", columnDefinition = "bytea")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime lastModified;

// Error
// org.hibernate.exception.SQLGrammarException: could not execute statement [ERROR: column \"last_modified\" is of type bytea but expression is of type smallint[]"}
// Hint: You will need to rewrite or cast the expression."}

版本号

'org.springframework. Boot :spring- Boot :3.2.0' 'org.postgresql:postgresql:42.5.4' 'org.hibernate. boot:hibernate-core:6.4.0.Final' Java 17

摘要

  • 能够推送新数据并从数据库中获取新数据,但数据库中的大小真的很大
  • 由于新旧数据大小不同,导致错误. java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class [Ljava.lang.Object; (java.time.LocalDateTime and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
a6b3iqyw

a6b3iqyw1#

发现修复。所以问题是Byte数组序列化时不转换为byte数组。这是奇怪的,不知道为什么。
首先在Entity中,与解决方案2相同。

@Column(name = "last_modified", columnDefinition = "bytea")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime lastModified;

字符串
然后将转换器更改为使用byte数组而不是Byte数组。

@Override
public byte[] convertToDatabaseColumn(final LocalDateTime localDateTime) {
    log.info("Inside convertToDatabaseColumn");
    if (localDateTime == null) {
        return null;
    }
    try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            final ObjectOutputStream oos = new ObjectOutputStream(buffer)) {
        oos.writeObject(localDateTime);
        log.info("buffer size: {}", buffer.size());
        return buffer.toByteArray();
    } catch (Exception e) {
        lalalalala
    }
}

@Override
public LocalDateTime convertToEntityAttribute(final byte[] bytes) {
    if (bytes == null) {
        return null;
    }
    try (final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            final ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
        final LocalDateTime dateTime = LocalDateTime.parse(objectInputStream.readObject().toString());
        return dateTime;
    } catch (Exception e) {
        lalalal
    }
}

相关问题