在开发过程中有很多业务需要动态生成sql才能完成,例如前端展示某物品时就需要对物品进行分页,排序。这就需要需要至少传入四个参数,第几页,页大小,排序字段,升序还是降序。根据这四个参数动态生成sql。mybatis中提供使用xml和annotation的方式管理sql语句。这里介绍使用annotation的方式,因为annotation更多体现面向对象化。
annotation中动态生成sql有如下两种方式。
-
annotation中拼接sq
不太推荐这种方式,因为这种方法跟xml差多,需要其他的标签,严重影响代码的可读性。例如实现分页查询的动态sql如下:
@Select({"<script>" ,
"select name,price,num from bin_info.goods ",
"<if test='sortField!=null'> order by #{sortField} </if>",
"<if test='pageNumber!='' and pageSize!='''> limit #{pageNumber} offset #{pageSize} </if>",
"</script>"})
List<Goods> findGoods(PageDto dto);
-
annotation中引用provider
这种方式更对像化,需要引入一个provider类,provider主要完成sql的动态拼接,然后在mapper层通过反射的方式引用相应的sql,实现1中的逻辑如下两步:
首先,创建用于拼接动态sql的provider:
import com.channing.dto.PageDto;
import org.apache.ibatis.jdbc.SQL;
import java.util.Map;
/**
* @author :channing
* @date :Created in 5/12/2020 6:03 PM
* @description:${The sql provider for goods}
*/
public class GoodsSqlProvider {
public String findByPage(Map<String,PageDto> param){
PageDto pageDto = param.get("page_dto");
String pageString = new SQL(){
{//notice: here used code block, if don't use,the following sql FUNCTION can not be used.
SELECT("name,price,num");
FROM("bin_info.goods");
String sortField = pageDto.getSortField();
if(sortField!=null) ORDER_BY(sortField);
if(pageDto.getPageNumber()!=null && pageDto.getPageSize()!=null) {
LIMIT(pageDto.getPageNumber().intValue());
OFFSET(pageDto.getPageSize().intValue());
}
}
}.toString();
return pageString;
}
}
其次,定义mapper中的接口:
@SelectProvider(method = "findByPage",type=GoodsSqlProvider.class)
List<Goods> findGoods(@Param("page_dto")PageDto dto);
本文中使用的PageDto如下,其中使用Long类型是因为可以设为null,当为null时 相应的参数可以不用拼到sql中,如果使用long的话,每次必须进行分页。
import lombok.Data;
/**
* @author :channing
* @date :Created in 5/12/2020 5:09 PM
* @description:${The page Dto contains four 4 parameters, dynamic sql will be based on them.}
*/
@Data
public class PageDto {
private Long pageNumber;
private Long pageSize;
private String sortField;
private String sortOrder;
}
注:本文中使用的是postgresql