无SQL内容的Java create PreparedStatement

无SQL内容的Java create PreparedStatement,java,jdbc,prepared-statement,Java,Jdbc,Prepared Statement,是否可以在java中创建PreparedStatement,而不设置初始SQL查询 示例代码: @Override public List<AccountBean> search(AccountConstraint... c) { if (c.length == 0) { throw new IllegalArgumentException("dao.AccountDAO.search: c.length == 0"); } try {

是否可以在java中创建
PreparedStatement
,而不设置初始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);
    }
}

另外,我在一个
try{}
中得到了两条语句,因为使用了资源进行了尝试。

在包装好准备好的语句后,您不能通过API修改它。没有SQL语句也无法创建它

为什么不单独创建查询,然后绑定参数?您可以使用映射来保存参数占位符及其值,以便将它们设置为准备好的语句


尽管我只是使用Spring的JDBC模板来更快地完成同样的事情。

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

据我所知,您希望使用Java编译器来帮助您动态定义查询。为什么不在
compile()
方法中创建准备好的语句,作为构建器的结果呢。此外,如果使用生成器模式,使对
add()
的每次调用都返回
this
,则代码的可读性会更高,更类似于声明性查询。然后您可以这样编写查询:

PreparedStatement ps = new QueryBuilder()
   .select("*")
   .from("accounts")
   .where()
   .add(yourConstraint())
   ...
   .compile();
但是,必须在循环之前创建准备好的语句。否则,如果在循环中保留对构建器的引用并调用
compile()
,则每次调用都会得到一条新的准备语句。因此,重用预编译查询不会带来好处。在循环中,您只为准备好的语句中的变量赋值。

如何改进SQL查询生成器 如果你看看如何做,你的想法是你更彻底地分离你的关注点。你应该:

  • SQL语句的表达式树表示(理想情况下不直接对字符串进行操作)
  • 方便地构造该表达式树的方法,例如通过使用DSL
  • 某种执行生命周期管理,生成SQL字符串、准备语句、绑定变量等
或者在代码中(jOOQ示例,但这也适用于您自己的查询生成器):

结果=
//这将通过jOOQ DSL构建表达式树
ctx.selectFrom(帐户)
.where(ac.getAccountIdConstraint())
.和(ac.getUsernameConstraint())
.和(ac.getPasswordConstraint())
.和(ac.getEmailConstraint())
//这将在内部创建PreparedStatement,绑定变量,执行它,并映射结果
.fetch();
当然,您的
AccountConstraint.getXYZConstraint()
方法不会返回SQL字符串片段,而是返回表达式树元素。在jOOQ的情况下,这将是一个

(免责声明:我为jOOQ的供应商工作)

如何提高SQL性能
我注意到,您对N
AccountConstraint
值运行N个查询,并以一种方式混合结果,使哪个
AccountConstraint
值产生哪个
AccountBean
无关紧要。我强烈建议您将该循环移动到生成的SQL查询中,因为您将在几乎所有数据库上获得更快的结果

使用“assist”我的意思是,如果您有拼写错误,而不是只会在运行时导致异常的纯SQL,您将得到编译器错误。但是,在您构建如此广泛的API之前,请快速搜索一下它是否已经存在:-)
PreparedStatement ps = new QueryBuilder()
   .select("*")
   .from("accounts")
   .where()
   .add(yourConstraint())
   ...
   .compile();
Result<?> result =

// This constructs the expression tree through the jOOQ DSL
ctx.selectFrom(ACCOUNTS)
   .where(ac.getAccountIdConstraint())
   .and(ac.getUsernameConstraint())
   .and(ac.getPasswordConstraint())
   .and(ac.getEmailConstraint())

// This internally creates a PreparedStatement, binds variables, executes it, and maps results
   .fetch();