使用 PreparedStatement 附加到查询

Appending to a query using PreparedStatement

我有以下查询 PostgreSQL 数据库的函数片段:

private void setQuery(String col1, String col2, String col3) {
   StringBuilder stringBuilder = new StringBuilder();
   stringBuilder.append(
      " SELECT  t1.id,t1.uuid, t2.client_id,t1.start_time, t1.end_time, t1.state FROM t1, t2 WHERE  t1.id=t2.id"
   );

   if (col1 != null && !col1.isEmpty()) {
     stringBuilder.append(" AND t1.col1 = ?");
   }
   if (col2 != null && !col2.isEmpty()) {
     stringBuilder.append(" AND t1.col2 = ?");
   }
   if (col3 != null && !col3.isEmpty()) {
     stringBuilder.append(" AND t1.col3 = ?");
   }
   PreparedStatement pstmt = null;
   try (Connection connection = connectionProvider.getConnection()) {
     pstmt = connection.prepareStatement(stringBuilder.toString());
     // how can I set the ? values in the stringBuilder, since they can be empty?
     // pstmt.setString(1, col1);
     // pstmt.setString(2, col2);
     // pstmt.setString(3, col3);
   } finally {
     if (pstmt != null) pstmt.close();
   }
}

注意 col1col2col3 可以为空或 null,我需要 add/remove 来自 SQL 查询的那些变量,以防它们empty/null 与否。理想情况下,我希望被允许附加到 PreparedStatement,但我不知道这怎么可能。 实现这一目标的最佳方法是什么?如何将值正确设置到准备好的语句中?

你可以试试这个方法:

private void setQuery(String col1, String col2, String col3) throws SQLException {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(
        " SELECT t1.id, t1.uuid, t2.client_id, t1.start_time, t1.end_time, t1.state FROM t1, t2 WHERE t1.id = t2.id "
    );

    List<String> optionalParams = new ArrayList<>();

    if (col1 != null && !col1.isEmpty()) {
        stringBuilder.append(" AND t1.col1 = ?");
        optionalParams.add(col1);
    }
    if (col2 != null && !col2.isEmpty()) {
        stringBuilder.append(" AND t1.col2 = ?");
        optionalParams.add(col2);
    }
    if (col3 != null && !col3.isEmpty()) {
        stringBuilder.append(" AND t1.col3 = ?");
        optionalParams.add(col3);
    }

    try (Connection connection = connectionProvider.getConnection();
        PreparedStatement pstmt = connection.prepareStatement(stringBuilder.toString()) {
        for(int i = 1; i < optionalParams.size(); i++) {
            pstmt.setString(i, optionalParams.get(i));
        }
    }
}

一些提示:

  1. 你也可以把PreparedStatement放在try-with-resource语句中,然后去掉finally块。
  2. 如果您的 setQuery 不在循环中,您可以简单地使用 + 运算符而不是 StringBuilder 来缩短代码。