2013-06-29 40 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