You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JDBC与PostgreSQL持久化非标准数组及复合类型数组?

用JDBC持久化PostgreSQL数组的解决方案

一、处理PGInterval三维数组(对应interval[][][])

PostgreSQL JDBC驱动不支持直接通过setObject()传入PGInterval[][][],可以用以下两种方式解决:

方式1:手动拼接SQL数组格式字符串

将三维数组逐层转换为PostgreSQL可识别的interval数组语法,再通过setObject()传入并指定类型:

PGInterval[][][] pgIntervals = // 你的三维PGInterval数组
StringBuilder sb = new StringBuilder("{{{");
for (PGInterval[][] layer1 : pgIntervals) {
    sb.append("{");
    for (PGInterval[] layer2 : layer1) {
        sb.append("{");
        for (int i = 0; i < layer2.length; i++) {
            PGInterval interval = layer2[i];
            sb.append("interval '")
              .append(interval.getYears()).append(" years ")
              .append(interval.getMonths()).append(" months ")
              .append(interval.getDays()).append(" days ")
              .append(interval.getHours()).append(" hours ")
              .append(interval.getMinutes()).append(" minutes ")
              .append(interval.getSeconds()).append(" seconds'");
            if (i != layer2.length - 1) sb.append(", ");
        }
        sb.append("}");
        if (layer2 != layer1[layer1.length - 1]) sb.append(", ");
    }
    sb.append("}");
    if (layer1 != pgIntervals[pgIntervals.length - 1]) sb.append(", ");
}
sb.append("}}}");

String sql = "INSERT INTO your_table (interval_col) VALUES (?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setObject(1, sb.toString(), Types.ARRAY);
    pstmt.executeUpdate();
}

方式2:通过PGConnection逐层构建数组

获取底层PGConnection,从最内层开始逐层创建数组:

PGInterval[][][] pgIntervals = // 你的三维PGInterval数组
PGConnection pgConn = conn.unwrap(PGConnection.class);

// 构建最内层一维interval数组
Array[][] innerArrays = new Array[pgIntervals.length][pgIntervals[0].length];
for (int i = 0; i < pgIntervals.length; i++) {
    for (int j = 0; j < pgIntervals[i].length; j++) {
        Object[] intervalStrs = Arrays.stream(pgIntervals[i][j])
            .map(PGInterval::getValue)
            .toArray();
        innerArrays[i][j] = pgConn.createArrayOf("interval", intervalStrs);
    }
}

// 构建二维数组
Array[] middleArrays = Arrays.stream(innerArrays)
    .map(arr -> {
        try {
            return pgConn.createArrayOf("interval[]", arr);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    })
    .toArray(Array[]::new);

// 构建最终三维数组
Array finalArray = pgConn.createArrayOf("interval[][]", middleArrays);

String sql = "INSERT INTO your_table (interval_col) VALUES (?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setArray(1, finalArray);
    pstmt.executeUpdate();
}

二、处理OffsetDateTime二维数组(对应timestamptz[][])

OffsetDateTime是JDBC 4.2标准支持的类型,可通过以下方式处理多维数组:

方式1:用PGConnection逐层构建数组

OffsetDateTime[][] dateTimes = // 你的二维OffsetDateTime数组
PGConnection pgConn = conn.unwrap(PGConnection.class);

// 构建内层一维数组
Array[] innerArrays = Arrays.stream(dateTimes)
    .map(row -> {
        try {
            return pgConn.createArrayOf("timestamptz", row);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    })
    .toArray(Array[]::new);

// 构建最终二维数组
Array finalArray = pgConn.createArrayOf("timestamptz[]", innerArrays);

String sql = "INSERT INTO your_table (timestamptz_col) VALUES (?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setArray(1, finalArray);
    pstmt.executeUpdate();
}

方式2:转换为字符串数组后强制类型转换

将OffsetDateTime转为ISO格式字符串,再通过SQL强制转换为目标类型:

OffsetDateTime[][] dateTimes = // 你的二维OffsetDateTime数组
String[][] dateStrs = Arrays.stream(dateTimes)
    .map(row -> Arrays.stream(row)
        .map(OffsetDateTime::toString)
        .toArray(String[]::new))
    .toArray(String[][]::new);

String sql = "INSERT INTO your_table (timestamptz_col) VALUES (cast(? as timestamptz[][]))";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setObject(1, dateStrs);
    pstmt.executeUpdate();
}

三、处理复合类型的四维数组(Test[][][][]对应test[][][][])

需要先实现Java对象与PostgreSQL复合类型的映射,再逐层构建数组:

步骤1:让POJO实现SQLData接口

Test类必须实现SQLData,完成与数据库复合类型的读写转换:

class Test implements SQLData {
    Integer a;
    Integer b;
    private String sqlType;

    // 构造器、getter/setter省略

    @Override
    public String getSQLTypeName() throws SQLException {
        return "test";
    }

    @Override
    public void readSQL(SQLInput stream, String typeName) throws SQLException {
        this.sqlType = typeName;
        this.a = stream.readInt();
        this.b = stream.readInt();
    }

    @Override
    public void writeSQL(SQLOutput stream) throws SQLException {
        stream.writeInt(a != null ? a : 0); // 根据业务需求处理null值
        stream.writeInt(b != null ? b : 0);
    }
}

步骤2:注册复合类型映射

在连接中注册自定义复合类型与Java类的关联:

PGConnection pgConn = conn.unwrap(PGConnection.class);
pgConn.addDataType("test", Test.class);

步骤3:逐层构建四维复合数组

从最内层开始,用createArrayOf逐层创建多维数组:

Test[][][][] testArrays = // 你的四维Test数组
PGConnection pgConn = conn.unwrap(PGConnection.class);

// 构建最内层一维test数组
Array[][][] inner3D = new Array[testArrays.length][testArrays[0].length][testArrays[0][0].length];
for (int i = 0; i < testArrays.length; i++) {
    for (int j = 0; j < testArrays[i].length; j++) {
        for (int k = 0; k < testArrays[i][j].length; k++) {
            inner3D[i][j][k] = pgConn.createArrayOf("test", testArrays[i][j][k]);
        }
    }
}

// 构建二维数组
Array[][] middle2D = Arrays.stream(inner3D)
    .map(layer -> {
        try {
            return pgConn.createArrayOf("test[]", layer);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    })
    .toArray(Array[][]::new);

// 构建三维数组
Array[] middle1D = Arrays.stream(middle2D)
    .map(layer -> {
        try {
            return pgConn.createArrayOf("test[][]", layer);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    })
    .toArray(Array[]::new);

// 构建最终四维数组
Array finalArray = pgConn.createArrayOf("test[][][]", middle1D);

String sql = "INSERT INTO your_table (test_col) VALUES (?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setArray(1, finalArray);
    pstmt.executeUpdate();
}

内容的提问来源于stack exchange,提问作者the thinker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:15:23