7

所以我有一个简单的函数来从数据库中返回一些东西。然后我可以通过在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 子句吗?任何帮助,将不胜感激。

谢谢

4

8 回答 8

2

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

例子:

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

于 2013-03-18T18:22:04.720 回答
1

@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();

(顺便说一句,我没有测试这段代码,所以可能有错别字)

于 2013-03-19T08:43:04.620 回答
0

写if else语句即

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

if(username!=null)
stmt.setInt(2, username)
于 2013-03-18T18:03:57.260 回答
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();
}
于 2013-03-18T18:04:11.440 回答
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);
于 2013-03-18T18:06:22.837 回答
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();
  .......
}
于 2013-03-18T18:11:41.230 回答
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);
//.....
    }
于 2013-03-18T18:20:17.177 回答
0

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

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

于 2013-03-18T19:08:19.793 回答