是否可以创建 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 并将特定字符串附加到查询的末尾。
我认为有一些解决方法是可行的,例如不提供 PreparedStatement
到 QueryBuilder
你会给一个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/