SQL之解决where 1=1 问题及优化多条件查询

本文介绍了一种在Java中优化数据库多条件查询的方法,通过重构SQL拼接逻辑以提高查询效率,并展示了如何通过封装查询条件和参数来简化DAO层代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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());
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值