SQL之解決where 1=1 問題及優化多條件查詢
阿新 • • 發佈:2019-01-04
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));//拼接條件
}
你以為結束了嗎?並沒有,問題仍然存在:
- 如果查詢引數較多,此時query方法的引數 會出現爆炸式增長。
- 本著責任分離規則,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());
}