在開發過程中有很多業務需要動态生成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