如何使用 PostgreSQL JDBC 从数据库中读取 ArrayList<String> 字段

How to read ArrayList<String> field from database with PostgreSQL JDBC

我在获取数据库中存储的 ArrayList<String> 作为 VARCHAR[] 的值时遇到问题。

不知何故,当我调试时,我可以看到从数据库返回的值是:

我希望通过将 ArrayList<String> 转换为 VARCHAR[] 来存储它,当从数据库中读取时,我希望将 VARCHAR[] 转换为 ArrayList<String>

代码:

 public Message<ArrayList<String>> getPlayersInSession(Object data) throws SQLException, ClassNotFoundException {
        String sessionCode = (String) data;
        Session session = PostgreSQLJDBC.sessionJDBCInstance().getSession(sessionCode);

        //session.getPlayers() is the problem I have
        return new Message<>(Message.RequestCode.RECEIVE_PLAYERS_IN_SESSION, session.getPlayers());
(Message.RequestCode.RECEIVE_PLAYERS_IN_SESSION, players);
    }
public class Session {

    private int _id;
    private String _code;
    private ArrayList<String> _players;
    private ArrayList<Pair<String, String>> _leaderboard;

    public Session() {
        _code = "";
        _players = new ArrayList<>();
        _leaderboard = new ArrayList<>();
    }

    ...

}

public class SessionJDBC implements SessionSQL {

    private final Connection _connection;

    public SessionJDBC(String url, String user, String password) throws ClassNotFoundException, SQLException {
        Class.forName("org.postgresql.Driver");

        _connection = DriverManager.getConnection(url, user, password);

        if (!sessionTableExists()) createTable();
    }

    @Override
    public void createTable() throws SQLException {
        String sql = "CREATE TABLE session(" +
                "id SERIAL PRIMARY KEY," +
                "code VARCHAR," +
                "players VARCHAR[]," +
                "leaderboard VARCHAR[]" +
                ")";
        PreparedStatement ps = _connection.prepareStatement(sql);

        ps.executeUpdate();
    }

    @Override
    public void addSession(Session session) throws SQLException {
        String sql = "INSERT INTO session(code, players, leaderboard)"
                + "VALUES (?,?,?)";

        PreparedStatement ps = _connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

        ps.setString(1, session.getCode());
        ps.setArray(2, _connection.createArrayOf("VARCHAR", session.getPlayers().toArray()));
        ps.setArray(3, _connection.createArrayOf("VARCHAR", session.getLeaderboard().toArray()));

        ps.executeUpdate();

        ResultSet generatedKeys = ps.getGeneratedKeys();

        if (generatedKeys.next()) {
            session.setId(generatedKeys.getInt(1));
        }
    }

    @Override
    public void removeSession(Session session) throws SQLException {
        String sql = "DELETE FROM session WHERE id = ?";
        PreparedStatement ps = _connection.prepareStatement(sql);

        ps.setInt(1, session.getId());
        ps.executeUpdate();
    }

    @Override
    public Session getSession(String code) throws SQLException {
        return getAllSessions().stream().filter(session -> session.getCode().equals(code)).findFirst().orElse(null);
    }

    @Override
    public ArrayList<Session> getAllSessions() throws SQLException {
        ArrayList<Session> array = new ArrayList<>();

        ResultSet result = _connection.prepareStatement("SELECT * FROM session").executeQuery();

        while (result.next()) {
            Session session = new Session();

            session.setCode(result.getString("code"));
            session.setId(result.getInt("id"));
            session.setPlayers(new ArrayList(Collections.singletonList(result.getArray("players"))));
            session.setLeaderboard(new ArrayList(Collections.singletonList(result.getArray("leaderboard"))));

            array.add(session);
        }

        result.close();

        return array;
    }

    @Override
    public boolean sessionTableExists() throws SQLException {
        DatabaseMetaData dbm = _connection.getMetaData();
        ResultSet tables = dbm.getTables(null, null, "session", null);

        return tables.next();
    }

}

我不知道代码示例是如何编译的,因为调试器中显示的 ArrayList 实际上是 ArrayList<PgArray> 类型而不是 ArrayList<String>

问题出现在这些行中:

session.setPlayers(new ArrayList(Collections.singletonList(result.getArray("players"))));
session.setLeaderboard(new ArrayList(Collections.singletonList(result.getArray("leaderboard"))));

首先 result.getArray("players") 返回 java.sql.Array object, more specifically a PgArray 实现。要获取真正的底层数据,您需要做的是:

(String[])result.getArray("players").getArray();

下一个问题是您正在使用 Collections.singletonList()。它的作用是生成一个只有一个元素的 ArrayList。相反,您应该使用 Arrays.asList。完整解决方案:

session.setPlayers(new ArrayList(Arrays.asList((String[])result.getArray("players").getArray)));
session.setLeaderboard(new ArrayList(Arrays.asList((String[])result.getArray("leaderboard").getArray)));

关于此代码的另一件有趣的事情是,您正在 selecting 来自 table 的所有行,然后通过流式处理结果在内存中进行过滤。为什么不在 SQL 查询的 code 字段上 select?