将PostgreSQL结果集直接转换为Java字符串数组

在本文中,我们学习如何使用getArray()方法通过直接转换将 PostgreSQL 数组转换为String[]数组。此外,我们还探讨如何利用 Java Streams 展平和处理二维数组。

PostgreSQL 数组是一种功能,它允许我们在单个列中存储多个值。但是,在 Java 中检索这些数组时,我们可能需要将它们转换为更易于管理的数据结构,例如字符串数组。在本教程中,我们将探讨如何在 Java 中将PostgreSQL 数组从ResultSet转换为字符串数组。

理解 PostgreSQL 数组
在 PostgreSQL 中,数组是一种数据类型,允许我们在单个列中存储多个值。这些值可以是任何数据类型,包括字符串、整数和日期。例如,类型为TEXT[]的列可以保存文本值数组,例如 {'apple', 'banana', 'cherry'}。

此外,PostgreSQL 支持嵌套数组,使我们能够存储数组的数组。例如,类型为TEXT[][]的列可以包含更复杂的结构,如{{'apple', 'banana'}, {'cherry', 'date'}},其中每个元素本身都是一个文本值数组。

在 Java 中检索数组列时,我们可能希望将其转换为更熟悉的数据结构,例如字符串数组String[]或String[][]。此转换过程可确保在 Java 应用程序中有效地处理数据

设置依赖项和数据库连接
在深入研究将 PostgreSQL 数组转换为 Java 字符串数组的解决方案之前,我们需要设置项目环境。要使用 Java 与 PostgreSQL 数据库交互,我们需要在 Maven 项目中包含PostgreSQL JDBC 驱动程序。让我们将以下依赖项添加到pom.xml文件:

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

接下来,我们需要建立与 PostgreSQL 数据库的连接。这涉及指定数据库 URL、用户名和密码。以下方法演示如何创建Connection对象以与数据库交互:

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

在此代码片段中,connect()方法旨在为我们的 PostgreSQL 数据库创建并返回一个Connection对象。

准备一维测试数据
为了测试我们的数据转换和处理逻辑,我们需要设置适当的数据库表并插入示例数据。 我们首先创建一个名为test_table的 PostgreSQL 表,其中包含一个数组列。此列test_array的类型为TEXT[] ,用于存储文本值数组。

以下是创建test_table 的SQL 命令:

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

接下来我们在test_table中插入一些示例数据来表示一维数据:

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

创建 POJO 类
我们将创建一个 POJO 类TestRow,将从数据库检索到的数据映射到 Java 对象。TestRow类表示用于保存来自test_table的数据的简单结构。它包括两个字段:id和testArray:

public class TestRow {
    private int id;
    private String[] testArray;
    // getters and setters
}

转换一维数组
在这种方法中,我们使用getArray()方法将 PostgreSQL 数组转换为 Java String[]数组。此方法返回一个java.sql.Array对象,该对象可以转换为String[]数组。我们使用TestRow POJO 来封装每一行数据:

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) {
        // Handle exception
    }
    return resultList;
}

在这个方法中,我们首先执行 SQL 查询来检索test_table中的所有行,包括id和test_array列。然后我们遍历ResultSet中的每一行。

对于每一行,我们使用getArray()方法检索 PostgreSQL 数组,该方法返回一个java.sql.Array对象。接下来,我们通过强制转换将此java.sql.Array对象转换为String[]数组。

此外,我们使用行的id和转换后的String[]数组创建一个TestRow对象。这种方法将数据封装到结构化对象中,使其更易于使用。每个TestRow对象都添加到List中,然后返回该 List。

该方法很容易实现,只需要很少的代码即可将数据库数组转换为 Java 数组。但是,使用直接转换时,我们需要确保 PostgreSQL 数组中的所有元素都是可以表示为字符串的类型。

如果元素的类型不同(例如INTEGER[]),则会导致ClassCastException。为了解决这个问题,我们可以先将 PostgreSQL 数组转换为Object[],然后将每个元素转换为所需的类型,从而避免潜在的转换问题。

让我们验证我们的方法以确保它正常工作:

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])
    );
    // Compare each TestRow's array with the expected array
    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getTestArray(), result.get(i).getTestArray());
    }
}

在此测试中,我们验证convertAllArraysUsingGetArray()方法是否正确将 PostgreSQL 数组转换为 Java String[]数组。我们将结果与预期值进行比较以确保准确性。

准备二维测试数据
为了处理二维数组,我们将创建另一个名为nested_array_table的 PostgreSQL 表。此表包含一个名为nested_array的列,类型为TEXT[][],可以存储数组的数组。

以下是创建nested_array_table 的SQL 命令:

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

接下来,我们将示例数据插入到nested_array_table中来表示嵌套数组:

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

在此示例中,nested_array_table包含二维数组的行。

为二维数组创建 POJO 类
接下来,我们将创建一个NestedTestRow类来表示nested_array_table中的行。在本例中,nestedArray是一个二维字符串数组,由String[][] 表示:

public class NestedTestRow {
    private int id;
    private String[][] nestedArray;
    // getters and setters
}

处理嵌套数组
使用 PostgreSQL 时,经常会遇到嵌套数组,这在 Java 中处理起来可能很困难。以下方法演示如何将嵌套 PostgreSQL 数组转换为平面String[]数组:

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) {
        // Handle exception
    }
    return resultList;
}

在此方法中,我们将嵌套的 PostgreSQL 数组作为Object[][]检索。然后,我们使用 Java Streams将此Object[][]转换为String[][]。使用Object::toString将嵌套数组的每个元素转换为其字符串表示形式。

此转换是在嵌套映射操作中完成的,其中每个子数组在聚合到最终的String[][]数组之前都经过独立处理。然后,我们为每一行创建一个NestedTestRow对象并将其添加到结果列表中。

让我们创建一个测试方法来验证二维转换:

@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])
    );
    // Compare each NestedTestRow's array with the expected array
    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getNestedArray(), result.get(i).getNestedArray());
    }
}

本次测试验证convertNestedArraysToStringArray()方法能否正确将 PostgreSQL 二维数组转换为 Java String[][]数组,并将结果与​​预期值进行对比,确认转换的准确性。