【问题标题】:Hibernate convert existing Integer[] to String[] (bytea) in Postgres databaseHibernate 将 Postgres 数据库中现有的 Integer[] 转换为 String[] (bytea)
【发布时间】:2017-01-05 08:21:36
【问题描述】:

我正在使用 Spring、Hibernate 和 Postgres。 在我的一个模型类中,我有:

@Entity
class SomeData {
    private Long dataId;
    private String name;
    private Integer[] data;
}

它已被使用,并且我在数据库中有上述格式的数据。

“data”字段是bytea(在phppgadmin中可见)类型,db中保存的示例值之一是:

��ur[Ljava.lang.Integer;������xpsr...

问题是现在我需要将模型更改为

String[] data;

但是当我这样做时,Hibernate 无法读取这些数据,因为它的类型为 Integer。

我的问题 - 是否可以以某种方式将这些 Integer 数组对象转换为 String 数组对象?使用一些 db 工具、sql 查询或 Hibernate?

【问题讨论】:

  • 或在您的setData() 方法中,包括将Integer[] 转换为String[] 的逻辑
  • 问题是你为什么要存储序列化的Java对象?这几乎总是一个坏主意。最好将其存储为 Postgres 中的 int[] 或 text[] - 这样您还可以使用 SQL 来操作数据
  • @user3626048 您是否使用某种迁移工具来更改架构(例如 liquibase、flyway 等)?另外,您是否坚持新类型为String[]? (而不是适当的规范化,f.ex. @ElementCollection List<String>?)
  • @user3626048 如果您没有这样的工具,您只能使用您编写的自定义脚本更改您的架构并手动执行它们。您需要一些 java 代码来从表中读取序列化值,您没有其他选择。 -- 是的,规范化有时需要更多的表格,但这只会让你的结构更清晰,而不是复杂。复杂的是你目前的情况,因为缺乏规范化。

标签: java spring postgresql hibernate


【解决方案1】:

您需要编写一个转换算法才能运行一次。比如:

Connection c = ((SessionImplementor)entitymanager).connection();
boolean oldstate = c.getAutoCommit();
c.setAutoCommit(false);
Statement s = c.createStatement();
PreparedStatement ps = c.prepareStatement("UPDATE my_table SET data = ? WHERE id = ?");
ResultSet rs = s.executeQuery("SELECT id, data FROM my_table");
ByteArrayInputStream bais;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectInputStream ois;
ObjectOutputStream oos = new ObjectOutputStream(baos);
while (rs.next()) {
    long id = rs.getLong(1);
    byte[] bdata = rs.getBytes(2);
    bais = new ByteArrayInputStream(bdata);
    ois = new ObjectInputStream(bais);
    Integer[] olddata = (Integer[]) ois.readObject();
    String[] newdata = new String[olddata.length];
    for (int i = 0; i < olddata.length; i++) {
        Integer din = olddata[i];
        String dout = null;
        if (din != null) {
            dout = din.toString();
        }
        newdata[i] = dout;
    }
    oos.writeObject(newdata);
    oos.flush();
    ps.setLong(1, id);
    ps.setBytes(2, baos.toByteArray());
    baos.reset();
}
c.commit();
c.setAutoCommit(oldstate);

如果你想通过 Hibernate 来做,你需要一个辅助列,或者你必须将其更改为 Object[],运行转换,然后将其更改为 String[],但这不方便更新生产,效率也不高,因为你会在 Hibernate 中经历很多层的验​​证和转换。

但是,如果您选择在数据库本身内部使用数组类型,我目前提出了一个独立的模块,它允许它https://github.com/hibernate/hibernate-orm/pull/1499。我们没有不适用于它的测试用例,但如果您能找到任何需要修复的地方,那将有助于获得批准。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 2019-12-06
    • 1970-01-01
    • 2010-09-06
    • 2011-02-07
    相关资源
    最近更新 更多