2013-06-29 39 views
1

是否可以在没有设置初始SQL查询的情况下在java中创建PreparedStatementJava创建没有SQL内容的PreparedStatement

示例代码:

@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现在可以正确地实现了Builder模式。
  • QueryBuilder.add()一次接受多个Constraint s。
  • 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); 
    } 
} 

PS。由于试用资源,我在一个try{ }中得到两个陈述。

回答

5

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

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

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

但是,你必须在循环之前创建准备语句。否则,如果您保留对构建器的引用并在循环中调用compile(),则每次调用都会得到新的准备好的声明。所以你不会得到重用预编译查询的好处。在循环中,您只将值分配给准备好的语句中的变量。

+0

对于“帮助”,我的意思是如果您有拼写错误而不是普通的SQL,那么在运行时只会导致异常,您将得到编译器错误。 – avidD

1

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

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

虽然我只是使用Spring的JDBC模板来更快地完成相同的事情。

+0

对于Spring JDBC建议+1。 – duffymo