1. 引言

PostgreSQL数组允许我们在单列中存储多个值。但在Java中检索这些数组时,通常需要将其转换为更易处理的数据结构,如字符串数组。本教程将探讨如何将PostgreSQL数组从ResultSet转换为Java中的字符串数组。

2. 理解PostgreSQL数组

PostgreSQL数组是一种特殊数据类型,支持在单列中存储多个值:

  • 这些值可以是任意数据类型(字符串、整数、日期等)
  • 例如,TEXT[]类型的列可存储文本数组:{'apple', 'banana', 'cherry'}

PostgreSQL还支持嵌套数组:

  • 例如TEXT[][]类型可存储复杂结构:{{'apple', 'banana'}, {'cherry', 'date'}}
  • 每个元素本身也是文本数组

在Java中检索数组列时,通常需要转换为:

  • String[](一维数组)
  • String[][](二维数组)

这种转换确保数据能在Java应用中高效处理。

3. 设置依赖和数据库连接

3.1 添加Maven依赖

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.3</version>
</dependency>

3.2 建立数据库连接

static Connection connect() throws SQLException {
    String url = "jdbc:postgresql://localhost:5432/my_database";
    String user = "admin_user";
    String password = "secure_password";
    return DriverManager.getConnection(url, user, password);
}

⚠️ 注意:实际开发中应使用连接池(如HikariCP)而非直接DriverManager

4. 准备一维测试数据

4.1 创建测试表

CREATE TABLE test_table (
    id SERIAL PRIMARY KEY,
    test_array TEXT ARRAY
);

4.2 插入测试数据

INSERT INTO test_table (test_array) 
VALUES
  (ARRAY['apple', 'banana', 'orange']),
  (ARRAY['hello', 'world', 'java']),
  (ARRAY['postgresql', 'test', 'example']);

5. 创建POJO类

public class TestRow {
    private int id;
    private String[] testArray;

    // 构造器、getter和setter
}

最佳实践:使用POJO封装数据,避免直接操作原始ResultSet

6. 转换一维数组

6.1 核心转换方法

List<TestRow> convertAllArraysUsingGetArray() {
    List<TestRow> resultList = new ArrayList<>();
    try (Connection conn = connect(); Statement stmt = conn.createStatement()) {
        ResultSet rs = stmt.executeQuery("SELECT id, test_array FROM test_table");

        while (rs.next()) {
            int id = rs.getInt("id");
            Array array = rs.getArray("test_array");
            String[] testArray = (String[]) array.getArray();
            TestRow row = new TestRow(id, testArray);
            resultList.add(row);
        }
    } catch (SQLException e) {
        // 实际项目中应使用日志框架
        e.printStackTrace();
    }
    return resultList;
}

6.2 关键步骤解析

  1. 通过rs.getArray()获取java.sql.Array对象
  2. 使用array.getArray()转换为Java数组
  3. 直接强制转换为String[]

⚠️ 踩坑提醒

  • 当数组元素非字符串类型(如INTEGER[])会抛ClassCastException
  • 解决方案:先转Object[]再逐个处理

6.3 单元测试验证

@Test
void givenArray_whenUsingConvertArrays_thenReturnStringArray() throws SQLException {
    List<TestRow> result = convertAllArraysUsingGetArray();

    String[][] expectedArrays = {
        new String[]{"apple", "banana", "orange"},
        new String[]{"hello", "world", "java"},
        new String[]{"postgresql", "test", "example"}
    };
    
    List<TestRow> expected = Arrays.asList(
        new TestRow(1, expectedArrays[0]),
        new TestRow(2, expectedArrays[1]),
        new TestRow(3, expectedArrays[2])
    );

    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getTestArray(), result.get(i).getTestArray());
    }
}

7. 准备二维测试数据

7.1 创建嵌套数组表

CREATE TABLE nested_array_table (
    id SERIAL PRIMARY KEY,
    nested_array TEXT[][]
);

7.2 插入测试数据

INSERT INTO nested_array_table (nested_array) 
VALUES 
  (ARRAY[ARRAY['apple', 'banana'], ARRAY['cherry', 'date']]),
  (ARRAY[ARRAY['hello', 'world'], ARRAY['java', 'programming']]);

8. 创建二维数组POJO

public class NestedTestRow {
    private int id;
    private String[][] nestedArray;

    // 构造器、getter和setter
}

9. 处理嵌套数组

9.1 二维数组转换方法

List<NestedTestRow> convertNestedArraysToStringArray() {
    List<NestedTestRow> resultList = new ArrayList<>();
    try (Connection conn = connect(); Statement stmt = conn.createStatement()) {
        ResultSet rs = stmt.executeQuery("SELECT id, nested_array FROM nested_array_table");

        while (rs.next()) {
            int id = rs.getInt("id");
            Array array = rs.getArray("nested_array");
            Object[][] nestedArray = (Object[][]) array.getArray();
            String[][] stringNestedArray = Arrays.stream(nestedArray)
              .map(subArray -> Arrays.stream(subArray)
                .map(Object::toString)
                  .toArray(String[]::new))
              .toArray(String[][]::new);
            NestedTestRow row = new NestedTestRow(id, stringNestedArray);
            resultList.add(row);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return resultList;
}

9.2 转换流程详解

  1. 获取java.sql.Array对象
  2. 转换为Object[][](避免类型转换异常)
  3. 使用Java Stream处理:
    • 外层流处理子数组
    • 内层流将元素转为字符串
  4. 构建最终String[][]

优势

  • 类型安全,避免ClassCastException
  • 代码简洁,利用Stream API

9.3 二维数组测试

@Test
void givenNestedArray_whenUsingConvertNestedArrays_thenReturnStringNestedArray() throws SQLException {
    List<NestedTestRow> result = convertNestedArraysToStringArray();

    String[][][] expectedNestedArrays = {
        {
            { "apple", "banana" },
            { "cherry", "date" }
        },
        {
            { "hello", "world" },
            { "java", "programming" }
        }
    };

    List<NestedTestRow> expected = Arrays.asList(
        new NestedTestRow(1, expectedNestedArrays[0]),
        new NestedTestRow(2, expectedNestedArrays[1])
    );

    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getNestedArray(), result.get(i).getNestedArray());
    }
}

10. 总结

本文介绍了两种PostgreSQL数组转换方案:

一维数组转换

  • 方法:直接强制转换(String[]) array.getArray()
  • 适用场景:确定数组元素为字符串类型
  • 风险:类型不匹配时抛异常

二维数组转换

  • 方法:Stream API + Object::toString
  • 优势
    • 类型安全
    • 支持任意元素类型
    • 代码可读性高

关键要点

  1. 始终使用getArray()方法获取原始数组
  2. 复杂数组结构优先考虑Stream处理
  3. 用POJO封装数据提升可维护性
  4. 编写单元测试验证转换逻辑

完整示例代码可在GitHub仓库获取


原始标题:Convert a ResultSet From PostgreSQL Array to Array of Strings | Baeldung