MyBatis实现动态查询语句
一.为什么要使用动态查询语句?
废话,当然是为了代码的重用和简化操作接口,减少代码冗余。
二.什么情况下使用动态查询?
当页面中有多个查询类型相同但查询条件不同时,可以请求同一服务而带不同参数。
三.如何实现动态查询?
1.使用SQL类来动态生成SQL语句
由于@Select注解中不能进行逻辑判断,唯一能实现逻辑判断的只有java语言,故我们可以创建一个类来动态生成SQL语句,使用ibatis提供的SQL类可以创建SQL语句,具体如下:
package com.eshop.mapper.provider;
import com.mysql.jdbc.StringUtils;
import org.apache.ibatis.jdbc.SQL;
public class TypeSqlProvider {
public String dynamicTypeSql(String type, String brands, String words){
String sql=new SQL(){{
SELECT(" *, spt.id spt_id , sb.id sb_id");
FROM(" s_product sp ");
LEFT_OUTER_JOIN(" s_product_type spt ON sp.product_type=spt.id ");
LEFT_OUTER_JOIN(" s_brand sb ON sp.product_brand=sb.id ");
//jdbc驱动包中提供的一个字符串非空验证的方法
if(!StringUtils.isNullOrEmpty(type)){
WHERE(" sp.product_type=#{type} ");
}
if(!StringUtils.isNullOrEmpty(words)){
//以下两种方式对应的是jdbc中的Statement和PreparedStatement
//搜索历史模糊查询
WHERE(" sp.product_name like '%${words}%'");
//WHERE(" sp.product_name like \"%\"#{words}\"%\"");
}
if(!StringUtils.isNullOrEmpty(brands)){//brands中可能包含多个品牌id
//分离品牌字符串
String[] brandId_arr = brands.split(",");
String sql_brands=" sb.id in (";
for (int i = 0; i <brandId_arr.length ; i++) {
sql_brands+="'"+brandId_arr[i]+"'";
if(i<brandId_arr.length-1){
sql_brands+=",";
}
}
sql_brands+=")";
WHERE(sql_brands);
}
}}.toString();
return sql;
}
}
只需要使用if来判断各个参数是否为空,不为空则WHERE生效,最后返回SQL的.toString()转换为String类型的SQL语句。
2.使用MyBatis的@SelectProvider注解
上述类实现后,我们就可以在mapper层中使用@SelectProvider注解来利用反射来创建对象并使用其中的动态语句生成方法,具体在mapper层代码如下;
@SelectProvider(value = TypeSqlProvider.class,method="dynamicTypeSql")
@ResultMap("pro_type_brand")
List<Product> QueryProductsByParams(String type, String words, String brands);
其中参数value代表要使用的类类型,以创建实例,method就是我们要创建的实例要使用的方法,若查询返回字段名和实体属性名不同则需要手动映射,即使用Results和Result,由于我前面映射过,故在此直接使用@ResultMap注解调用前面的映射,然后我们就可以相继在Service层和Controller层中逐层调用。