Java创建没有SQL内容的PreparedStatement

标签 java jdbc prepared-statement

是否可以创建 PreparedStatement在 java 中而不设置初始 SQL 查询?

示例代码:

@Override
public List<AccountBean> search(AccountConstraint... c) {
    if (c.length == 0) {
        throw new IllegalArgumentException("dao.AccountDAO.search: c.length == 0");
    }
    try {
        List<AccountBean> beans = new ArrayList<>();
        for (AccountConstraint ac : c) {
            PreparedStatement ps = connection.prepareStatement(null);
            QueryBuilder queryBuilder = new QueryBuilder(ps, "SELECT * FROM accounts");
            queryBuilder.add(ac.getAccountIdConstraint());
            queryBuilder.add(ac.getUsernameConstraint());
            queryBuilder.add(ac.getPasswordConstraint());
            queryBuilder.add(ac.getEmailConstraint());
            //INSERT QUERY INTO PS
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                beans.add(new AccountBean(rs));
            }
        }
        return beans;
    } catch (SQLException ex) {
        throw new RuntimeException(ex);
    }
}

诀窍在于 QueryBuilder ,该类负责基于初始 SELECT 部分构建查询部分,然后添加相应的 WHERE 和 AND 子句。

然而,为了确保所有数据都是安全的,实际参数也必须放在 PreparedStatement 中,因此它被传递给 QueryBuilder。

每个 QueryBuilder.add()将一些参数添加到 PreparedStatement 并将特定字符串附加到查询的末尾。

我认为有一些解决方法是可行的,例如不提供 PreparedStatementQueryBuilder你会给一个List<Object>然后您将编写一个自定义函数,将它们放入 PreparedStatement 中稍后。

但是您对此有何看法和建议?

问候。

已添加解决方案

首先进行一些关键更改:

  • QueryBuilder现在正确地实现了构建器模式。
  • QueryBuilder.add()接受多个 Constraint马上。
  • AccountConstraint可以给出一个数组,它给出所有 Constraint现在。

@Override
public List<AccountBean> search(AccountConstraint... c) {
    if (c.length == 0) {
        throw new IllegalArgumentException("dao.AccountDAO.search: c.length == 0");
    }
    try {
        List<AccountBean> beans = new ArrayList<>();
        for (AccountConstraint ac : c) {
            try (PreparedStatement ps = new QueryBuilder("SELECT * FROM accounts").add(ac.getConstraints()).build();ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    beans.add(new AccountBean(rs));
                }
            }
        }
        return beans;
    } catch (SQLException ex) {
        throw new RuntimeException(ex);
    }
}

附言。我将两个语句合二为一try{ }因为 try-with-resources。

最佳答案

准备语句意味着编译它,以便您可以使用不同的参数高效地多次执行它。因此,不,在定义查询之前编译查询是没有意义的。

据我了解,您想使用 Java 编译器来帮助您动态定义查询。为什么不直接在 compile() 方法中创建准备好的语句,因此,作为构建器的结果。此外,如果您使用构建器模式以便每次调用 add() 都返回 this,您的代码将变得更具可读性并且更类似于声明式查询。然后你可以这样写你的查询:

PreparedStatement ps = new QueryBuilder()
   .select("*")
   .from("accounts")
   .where()
   .add(yourConstraint())
   ...
   .compile();

但是,您必须在循环之前创建预准备语句。否则,如果您保留对构建器的引用并在循环中调用 compile(),您将在每次调用时获得一个新的准备好的语句。因此,您不会获得重用预编译查询的好处。在循环中,您只需为准备好的语句中的变量赋值。

关于Java创建没有SQL内容的PreparedStatement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17380150/

相关文章:

java - 使用 : 的语句对象

java - 类型不匹配 : cannot convert from Connection to Connection

java - 使用 UCanAccess 连接到受工作组安全文件 (MDW) 保护的 MS Access 数据库

java - 使用准备好的语句和用户输入更新数据

php - 在准备好的语句中传递带有空格的参数

JavaFX java.lang.reflect.InitationTargetException(使用场景构建器)

java - 使用适用于 Android 应用程序的自定义适配器将项目动态添加到 ListView

java - 获取 JAXB 反/序列化期间的进度信息

java - 输入字符串 : "" 出现错误 java.lang.numberformatException

mysql - Rails 3 connection.execute IN语句参数数组语法