ski*_*iwi 2 java jdbc prepared-statement
是否可以PreparedStatement在不设置初始SQL查询的情况下在java中创建?
示例代码:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
诀窍在于QueryBuilder,此类负责基于初始SELECT部分构建查询的部分,然后添加相应的WHERE和AND子句.
但是,为了确保所有数据都是安全的,实际的参数也必须放在PreparedStatement中,因此它被传递给QueryBuilder的原因.
每个都QueryBuilder.add()在PreparedStatement中添加一些参数,并将特定字符串附加到查询的末尾.
我想一些解决方法是可能的,例如,而不是给人一种PreparedStatement给QueryBuilder你会给一个List<Object>,然后你会写这使他们在一个自定义函数PreparedStatement以后.
但你有什么想法,对此有何建议?
问候.
解决方案补充
首先几个关键变化:
QueryBuilder 现在正确实现Builder模式.QueryBuilder.add()Constraint一次接受多个s.AccountConstraint可以给出一个Constraint现在给出所有s 的数组.@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);
}
}
Run Code Online (Sandbox Code Playgroud)
PS.try{ }由于资源的尝试,我在一个中得到两个语句.
准备语句意味着编译它以便您可以使用不同的参数多次有效地执行它.因此,在定义查询之前编译查询没有意义.
据我所知,您希望使用Java编译器来帮助您动态定义查询.为什么不在一个compile()方法中创建预准备语句,因此,作为构建器的结果.此外,如果使用构建器模式以使每次调用add()返回,则代码变得更具可读性并且更像是声明性查询this.然后你可以像这样编写你的查询:
PreparedStatement ps = new QueryBuilder()
.select("*")
.from("accounts")
.where()
.add(yourConstraint())
...
.compile();
Run Code Online (Sandbox Code Playgroud)
但是,您必须在循环之前创建预准备语句.否则,如果您保留对构建器的引用并compile()在循环中调用,则每次调用都会得到一个新的预准备语句.因此,您将无法获得重用预编译查询的好处.在循环中,您只需为预准备语句中的变量赋值.