如果我不知道我将传入多少参数,如何使用预准备语句?

时间:2013-03-18 17:59:08

标签: java mysql

所以我有一个简单的函数来从数据库中返回一些东西。然后,我可以通过在 WHERE 子句中添加不同的参数来修改此查询。处理这个问题最优雅有效的方法是什么?

示例:

    public static getUsers(int id, string username, string email) {

        Connection conn = null;
        PreparedStatement stmt = null;
        String sql = "";

        sql = "SELECT * FROM users " .........

这就是我对where子句感到困惑的地方。如果我做了像

这样的事情
"WHERE id = ? AND username = ? AND email = ?";   

如果我只使用ID调用方法,没有用户名或电子邮件,会发生什么?它会破裂,我不能发生这种情况。

另外,管理我的索引变得很难,因为如果我会做stmt.setInt(1, id)这样的事情,但是如果我只想用用户名调用该方法,并且该id将以null形式出现,那么该怎么办?投掷NPE?

我对Java不熟悉,抱歉......但我想我应该使用覆盖?我应该在条件语句中构建我的where子句吗?任何帮助,将不胜感激。

谢谢

8 个答案:

答案 0 :(得分:2)

我将创建一个实现Builder Pattern的SqlQuery类。 This是一篇很好的文章,解释了模式的用法。

示例:

public class SqlQuery {
    private StringBuilder tableQuery = new StringBuilder();
    private StringBuilder whereQuery = new StringBuilder();

    public SqlQuery(String selection, String table) {
        tableQuery.append("SELECT ").append(selection).append(" FROM ").append(table);
    }

    public SqlQuery addWhereClause(String parameter, String value) {
        if (whereQuery.length() == 0) {
            whereQuery.append(" WHERE ");
        }
        else {
            whereQuery.append(" AND ");
        }
        whereQuery.append(parameter).append(" = ").append(value);
        return this;
    }

    public String toString() {
        return tableQuery.toString() + whereQuery.toString();
    }
}

SqlQuery sqlQ = new SqlQuery("*", "users")
                  .addWhereClause("id", "2")
                  .addWhereClause("email", "test");
System.out.println(sqlQ);

打印:

  

SELECT * FROM users WHERE id = 2 AND email = test

答案 1 :(得分:0)

写if else语句,即

 if(username!=null)
 query=query+"username=?";

if(username!=null)
stmt.setInt(2, username)

答案 2 :(得分:0)

我会做这样的事情,创建一个接受List<ColumnNames>的方法,并在该方法中通过将占位符附加到列名称来循环遍历所有列名。

public List<Something> method(List<Something> list){

String sql = "SELECT * FROM users WHERE "+ this.processPlaceHolders(list);

}

public String processPlaceHolders(List<Something> list) {
StringBuilder finalStr=new StringBuilder("");
for(int i=0;i<list.size(); i++){
if(i==list.size()-1){
finalStr.append(list.get(i)+"=" +"?"); 
}
else {
   finalStr.append(list.get(i)+"=" +"?,");
}
}
return finalStr.toString();
}

答案 3 :(得分:0)

您需要动态构建SQL查询才能实现此目的。

public static getUsers(int id, string username, string email) {

    Connection conn = null;
    PreparedStatement stmt = null;
    String sql = "";

    sql = "SELECT * FROM users where id=? ";
    if (username != null)
      sql += " AND username=? ";
    if (email !=null)
      sql += " AND email=?";

    stmt = conn.prepareStatement(sql);
    stmt.setInt(1,id);
    if (username != null && email !=null)
    {
      stmt.setString(2,username);
      stmt.setString(3,email);
    }
    else if (username != null)
      stmt.setString(2,username);
    else if (email != null)
      stmt.setString(2,email);

答案 4 :(得分:0)

您的问题的解决方案是这样的:

public void getRecord(String id, String username, String email)
{
  String sql = " select * from users ";
  boolean isID , isUserName, isEmail;
  boolean isFirst = true;
  if (id!=null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       isFirst = false;
     }
     sql =  sql + " id = ?";
     isID = true;
  }
  if (username != null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       sql =  sql + " username = ?";
       isFirst = false;
     }
     else
     sql =  sql + " and username = ?";
     isUserName = true;
  }
  if (email != null)
  {
     if ( isFirst)
     {
       sql = sql + " where";
       sql = sql + " email = ?";
       isFirst = false;
     }
     else
     sql = sql + " and email = ?";
     isEmail = true;
  }
  PreparedStatement pst = con.prepareStatement(sql);
  int counter = 1;
  if (isID)
  pst.setString(counter++,id);
  if (isUserName)
  pst.setString(counter++,username);
  if (isEmail)
  pst.setString(counter++,email);
  //Then execute the query
  ResultSet rs = pst.executeQuery();
  .......
}

答案 5 :(得分:0)

试试这个:

public static getUsers(int id, String username, String email) {
        Connection conn = null;
        PreparedStatement stmt = null;
        String sql = "SELECT * FROM users WHERE id=? ";

        if (username != null && username.trim().length() != 0) sql = sql + " AND username=? "; 
        if (email != null && email.trim().length() != 0) sql = sql + " AND username=? ";

        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, id);

        if (username != null && username.trim().length() != 0) stmt.setString(2, username);
        if (email != null && email.trim().length() != 0) stmt.setString(3, email);
//.....
    }

答案 6 :(得分:0)

您应该考虑为每个有效的输入组合编写一个单独的方法,而不是编写一个非常复杂的方法来动态构造PreparedStatement。然后每个人都可以轻松验证其输入,并始终使用特定的PreparedStatement。这不仅会在将来更容易理解和维护,而且更容易测试。

如果您需要与现有API向后兼容,则可以编写一个getUsers(int id, string username, string email)方法,根据需要委派给更简单的方法。

答案 7 :(得分:0)

来自@ghdalum的好主意实际上并不涉及PreparedStatement。以下是我对他的建造者想法的改编,以制作PreparedStatement:

public class UserQueryBuilder {

    private Connection conn;
    private StringBuilder query = new StringBuilder("SELECT * FROM users");
    private List<ValueSetter> valueSetters = new ArrayList<ValueSetter>();

    // callback interface for setting the column values
    private interface ValueSetter {
        void setValue(PreparedStatement ps);
    }

    // the caller is responsible for closing the connection afterwards
    public QueryBuilder(Connection conn) {
        this.conn = conn;
    }           

    public QueryBuilder byId(final Integer id) {
        appendSeparator();
        query.append("id = ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setInt(id);
            }
        });
        return this;
    }   

    public QueryBuilder byEmail(String email) {
        appendSeparator();
        query.append("email = ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setString(email);
            }
        });
        return this;
    }   

    public QueryBuilder byUsername(String username) {
        appendSeparator();
        query.append("username= ?");
        valueSetters.add(new ValueSetter() {
            public void setValue(PreparedStatement ps) {
                ps.setString(username);
            }
        });
        return this;
    }

    private void appendSeparator() {
        if (filterValues.size() == 0) {
            query.append(" WHERE ")
        }
        else {
            query.append(" AND ")
        }
    }

    public PreparedStatment build() {
        PreparedStatement ps = conn.prepareStatement(query.toString());
        for(ValueSetter valueSetter : valueSetters) {
            valueSetter.setValue(ps);
        }
        return ps;
    }
}

用法:

PreparedStatement userQuery = new UserQueryBuilder(conn)
                              .byId("2")
                              .byEmail("test")
                              .build();
userQuery.execute();

(顺便说一句,我没有测试这段代码所以可能会出现拼写错误)