1. 程式人生 > >SQL之解決where 1=1 問題及優化多條件查詢

SQL之解決where 1=1 問題及優化多條件查詢

Dao中實現多條件查詢。

public List<Product> query(String name ,BigDecimal minSalePrice,
        BigDecimal maxSalePrice){
    QueryRunner runner = new QueryRunner(C3p0Utils.getDateSource());

    StringBuilder sql = new StringBuilder("select  * from product where 1=1 ");
    List<product > params
= new ArrayList<>();//存放參數 if(hasLength(name)){ sql.append(" and productName like ?");//注意空格 params.add("%"+name+"%"); } if(hasLength(minSalePrice)){ sql.append(" and salePrice >= ?");//注意空格 params.add(minSalePrice); } if(hasLength(maxSalePrice)){ sql.
append(" and salePrice <= ?");//注意空格 params.add(maxSalePrice); } return runner.query(sql,new BeanListHandler(Product.class),params.toArray()); }

但是使用WHERE 1=1 之後,就不能使用索引了,從MySQL5.7開始,會自動預設取消掉SQL中第一個為true的條件,而且每一條資料都得查詢一遍,效率低。

如何解決WHERE 1=1 的問題

(加個flag)
boolean isFirst = ture;

if
(hasLength(條件1)){ if(isFirst){ sql.append(" where ");//注意空格 isFirst=false; }else{ sql.append(" and "); //注意空格 } sql.append("productName like ? "); params.add("%"+name+"%"); } if(hasLength(條件2)){ if(isFirst){ sql.append(" where ");//注意空格 isFirst=false; }else{ sql.append(" and ");//注意空格 } sql.append("salePrice >= ?"); params.add(minSalePrice); } if(hasLength(條件3)){ if(isFirst){ sql.append(" where ");//注意空格 isFirst=false; }else{ sql.append(" and ");//注意空格 } sql.append("salePrice <= ?"); params.add(maxSalePrice); }

好多重複的 if else 好煩人。

所以換個思想,我把查詢條件放在一個集合中,我用的時候自己取,取出來的第一個 就是第一個我拼上“where”,之後的我都拼上“and”。

//封裝查詢條件
private List<String> conditions = new ArrayLIst<>();

if(hasLength(條件1)){
    conditions.add("pName like ?");
    params.add("%"+name+"%");
}
if(hasLength(條件2)){
    conditions.add("maxSalePrice <= ?");
    params.add(minSalePrice);
}
if(hasLength(條件3)){
    conditions.add("minSalePrice >= ?");
    params.add(maxSalePrice);
}
for(int i=0 ; i< conditions.size() ; i++){
    if(i=0){
        sql.append(" where ");//注意加空格 
    }else{
        sql.append(" and ");//注意加空格
    }
    sql.append(conditions.get(i));//拼接條件
}

你以為結束了嗎?並沒有,問題仍然存在:

  1. 如果查詢引數較多,此時query方法的引數 會出現爆炸式增長。
  2. 本著責任分離規則,dao應該只做CRUD,拼接sql 應該交給別人去做。

所以,
新建query包 放置處理查詢問題 的類來封裝查詢資訊。

public class ProductQuery{
    private String name;
    private BigDecimal minSalePrice;
    private BigDecimal maxSalePrice;
    //省略getter&&setter&&toString
    //封裝查詢條件
    private List<String> conditions = new ArrayLIst<>();
    //封裝查詢引數(list 允許重複 且 存取有序)
    private List<Object> parameters = new ArrayList<>();
    //返回拼接好的查詢條件:where 條件1 and 條件2 ...
    public String getQuery(){
        StringBuilder sql = new StringBuilder(200);
        if(hasLength(條件1)){
            conditions.add("pName like ?");
            parameters.add("%"+name+"%");
        }
        if(hasLength(條件2)){
            conditions.add("maxSalePrice <= ?");
            parameters.add(minSalePrice);
        }
        if(hasLength(條件3)){
            conditions.add("minSalePrice >= ?");
            parameters.add(maxSalePrice);
        }
        for(int i=0 ; i< conditions.size() ; i++){
            if(i=0){
                sql.append(" where ");//注意加空格 
            }else{
                sql.append(" and ");//注意加空格
            }
            sql.append(conditions.get(i));//拼接條件
        }
        return sql.toString();
    }
    //返回查詢引數
    public List<Object> getParamters(){
        return this.parameters;
    }
}

此時的Dao:

public List<Product> query(ProductQuery q){
    QueryRunner runner = new QueryRunner(C3p0Utils.getDateSource());
    String sql="select * from product"+q.getQuery();
    return runner.query(sql,q.getParameters().toArray);
}

有沒有很舒服?反正博主很喜歡 (- -)。

另外告訴大家上面的hasLength()方法:

public boolean hasLength(String str){
    return str!=null && !"".equals(str.trim());
}