MyBatis-Plus 多字段排序详解
·
MyBatis-Plus 多字段排序详解
1. 基本多字段排序
QueryWrapper 方式
java
// 多个字段排序:按年份降序,按状态升序,按创建时间降序
QueryWrapper<CapitalInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("capital_year") // 第一排序:年份降序
.orderByAsc("capital_state") // 第二排序:状态升序
.orderByDesc("create_time"); // 第三排序:创建时间降序
List<CapitalInfo> list = capitalInfoMapper.selectList(queryWrapper);
LambdaQueryWrapper 方式
java
// Lambda方式多字段排序
LambdaQueryWrapper<CapitalInfo> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.orderByDesc(CapitalInfo::getCapitalYear) // 年份降序
.orderByAsc(CapitalInfo::getCapitalState) // 状态升序
.orderByDesc(CapitalInfo::getCreateTime); // 创建时间降序
List<CapitalInfo> list = capitalInfoMapper.selectList(lambdaWrapper);
2. 高级排序方法
2.1 orderBy() 方法
java
// orderBy(boolean condition, boolean isAsc, R... columns)
// condition: 是否应用排序,isAsc: 是否升序,columns: 排序字段
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 动态条件排序
boolean needSort = true;
boolean isAsc = false; // 降序
wrapper.orderBy(needSort, isAsc, "capital_year", "create_time");
// 等价于:ORDER BY capital_year DESC, create_time DESC
// Lambda方式
LambdaQueryWrapper<CapitalInfo> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.orderBy(needSort, isAsc,
CapitalInfo::getCapitalYear,
CapitalInfo::getCreateTime);
2.2 orderByAsc() 和 orderByDesc() 单个字段
java
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 混合升降序
wrapper.orderByAsc("capital_state") // 状态升序
.orderByDesc("capital_year") // 年份降序
.orderByAsc("capital_type") // 类型升序
.orderByDesc("create_time"); // 创建时间降序
// 生成的SQL: ORDER BY capital_state ASC, capital_year DESC,
// capital_type ASC, create_time DESC
2.3 多字段统一升降序
java
// 多个字段统一升序
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
wrapper.orderByAsc(Arrays.asList("capital_year", "capital_state", "create_time"));
// 等价于: ORDER BY capital_year ASC, capital_state ASC, create_time ASC
// 多个字段统一降序
wrapper.orderByDesc(Arrays.asList("capital_year", "capital_state", "create_time"));
// 等价于: ORDER BY capital_year DESC, capital_state DESC, create_time DESC
// Lambda方式
LambdaQueryWrapper<CapitalInfo> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.orderByAsc(Arrays.asList(
CapitalInfo::getCapitalYear,
CapitalInfo::getCapitalState,
CapitalInfo::getCreateTime
));
3. 动态条件排序
3.1 根据参数动态排序
java
public List<CapitalInfo> queryWithDynamicSort(CapitalInfoQueryDTO queryDTO,
String sortField,
String sortOrder) {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 构建查询条件
if (StringUtils.isNotBlank(queryDTO.getCapitalName())) {
wrapper.like("capital_name", queryDTO.getCapitalName());
}
// 动态排序
if (StringUtils.isNotBlank(sortField)) {
if ("asc".equalsIgnoreCase(sortOrder)) {
wrapper.orderByAsc(sortField);
} else {
wrapper.orderByDesc(sortField);
}
} else {
// 默认排序
wrapper.orderByDesc("create_time").orderByAsc("capital_state");
}
return capitalInfoMapper.selectList(wrapper);
}
3.2 多字段动态排序
java
public List<CapitalInfo> queryWithMultiSort(CapitalInfoQueryDTO queryDTO,
List<SortItem> sortItems) {
QueryWrapper<CapitalInfo> wrapper = buildQueryWrapper(queryDTO);
// sortItems: [{"field":"capitalYear","order":"desc"},
// {"field":"capitalState","order":"asc"}]
if (CollectionUtils.isNotEmpty(sortItems)) {
for (SortItem item : sortItems) {
if ("asc".equalsIgnoreCase(item.getOrder())) {
wrapper.orderByAsc(item.getField());
} else if ("desc".equalsIgnoreCase(item.getOrder())) {
wrapper.orderByDesc(item.getField());
}
}
}
return capitalInfoMapper.selectList(wrapper);
}
// 排序项DTO
@Data
class SortItem {
private String field; // 排序字段
private String order; // asc/desc
}
4. 复杂排序场景
4.1 条件排序
java
public List<CapitalInfo> queryWithConditionalSort(CapitalInfoQueryDTO queryDTO) {
LambdaQueryWrapper<CapitalInfo> wrapper = new LambdaQueryWrapper<>();
// 根据资金状态决定排序规则
if (queryDTO.getCapitalState() != null && queryDTO.getCapitalState() == 1) {
// 状态为1时:按年份降序,创建时间升序
wrapper.orderByDesc(CapitalInfo::getCapitalYear)
.orderByAsc(CapitalInfo::getCreateTime);
} else {
// 其他状态:按类型升序,年份降序
wrapper.orderByAsc(CapitalInfo::getCapitalType)
.orderByDesc(CapitalInfo::getCapitalYear);
}
return capitalInfoMapper.selectList(wrapper);
}
4.2 自定义排序函数
java
// 使用 orderBySql 实现自定义排序
public List<CapitalInfo> queryWithCustomSort() {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 使用SQL函数排序
wrapper.orderByAsc("FIELD(capital_state, 2, 1, 3, 0)"); // 自定义顺序
wrapper.orderByDesc("LENGTH(capital_name)"); // 按名称长度排序
// 按条件排序:状态为1的排前面
wrapper.orderByDesc("CASE WHEN capital_state = 1 THEN 1 ELSE 0 END");
return capitalInfoMapper.selectList(wrapper);
}
4.3 分组后排序
java
public List<CapitalInfo> queryWithGroupByAndSort() {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 分组统计并排序
wrapper.select("capital_type", "capital_source", "COUNT(*) as count")
.groupBy("capital_type", "capital_source")
.orderByDesc("count") // 按数量降序
.orderByAsc("capital_type"); // 按类型升序
return capitalInfoMapper.selectList(wrapper);
}
5. 分页查询中的排序
5.1 分页排序
java
public IPage<CapitalInfo> queryPageWithSort(CapitalInfoQueryDTO queryDTO,
Integer pageNum,
Integer pageSize) {
Page<CapitalInfo> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<CapitalInfo> wrapper = new LambdaQueryWrapper<>();
// 构建查询条件
if (StringUtils.isNotBlank(queryDTO.getCapitalName())) {
wrapper.like(CapitalInfo::getCapitalName, queryDTO.getCapitalName());
}
// 排序条件
wrapper.orderByDesc(CapitalInfo::getCapitalYear)
.orderByAsc(CapitalInfo::getCapitalState)
.orderByDesc(CapitalInfo::getCreateTime);
return capitalInfoMapper.selectPage(page, wrapper);
}
5.2 分页参数包含排序
java
@Data
public class PageQueryDTO {
private Integer pageNum = 1;
private Integer pageSize = 10;
private List<SortItem> sortItems; // 排序字段列表
}
public IPage<CapitalInfo> queryPage(PageQueryDTO pageQuery,
CapitalInfoQueryDTO queryDTO) {
Page<CapitalInfo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
LambdaQueryWrapper<CapitalInfo> wrapper = new LambdaQueryWrapper<>();
// 构建查询条件
buildQueryWrapper(wrapper, queryDTO);
// 应用排序
applySort(wrapper, pageQuery.getSortItems());
return capitalInfoMapper.selectPage(page, wrapper);
}
private void applySort(LambdaQueryWrapper<CapitalInfo> wrapper, List<SortItem> sortItems) {
if (CollectionUtils.isEmpty(sortItems)) {
// 默认排序
wrapper.orderByDesc(CapitalInfo::getCreateTime);
return;
}
for (SortItem item : sortItems) {
switch (item.getField()) {
case "capitalYear":
applyOrder(wrapper, CapitalInfo::getCapitalYear, item.getOrder());
break;
case "capitalState":
applyOrder(wrapper, CapitalInfo::getCapitalState, item.getOrder());
break;
case "createTime":
applyOrder(wrapper, CapitalInfo::getCreateTime, item.getOrder());
break;
// 其他字段...
}
}
}
private <T> void applyOrder(LambdaQueryWrapper<CapitalInfo> wrapper,
SFunction<CapitalInfo, T> column,
String order) {
if ("asc".equalsIgnoreCase(order)) {
wrapper.orderByAsc(column);
} else {
wrapper.orderByDesc(column);
}
}
6. 性能优化建议
6.1 排序索引优化
java
// 为常用排序字段添加索引
public List<CapitalInfo> queryOptimized() {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 优先使用有索引的字段排序
wrapper.orderByAsc("id") // 主键索引,排序效率高
.orderByDesc("capital_year_indexed") // 有索引的字段
.orderByAsc("capital_state");
return capitalInfoMapper.selectList(wrapper);
}
6.2 限制排序数据量
java
public List<CapitalInfo> queryWithLimit() {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 先筛选再排序,减少排序数据量
wrapper.eq("capital_state", 1)
.orderByDesc("create_time")
.last("LIMIT 1000"); // 限制结果集大小
return capitalInfoMapper.selectList(wrapper);
}
6.3 避免文件排序
java
public List<CapitalInfo> queryAvoidFileSort() {
QueryWrapper<CapitalInfo> wrapper = new QueryWrapper<>();
// 确保where条件中的字段和order by字段有复合索引
wrapper.eq("capital_year", 2024)
.eq("capital_type", "A")
.orderByAsc("capital_state") // 复合索引(capital_year, capital_type, capital_state)
.orderByDesc("create_time");
return capitalInfoMapper.selectList(wrapper);
}
7. 最佳实践总结
java
@Service
public class CapitalInfoService {
public List<CapitalInfo> queryWithBestPractice(CapitalInfoQueryDTO queryDTO) {
// 推荐使用Lambda方式
LambdaQueryWrapper<CapitalInfo> wrapper = new LambdaQueryWrapper<>();
// 1. 先构建查询条件
buildQueryConditions(wrapper, queryDTO);
// 2. 应用排序规则(清晰明了)
applySortRules(wrapper, queryDTO);
// 3. 如果需要分页
// Page<CapitalInfo> page = new Page<>(pageNum, pageSize);
// return capitalInfoMapper.selectPage(page, wrapper);
return capitalInfoMapper.selectList(wrapper);
}
private void buildQueryConditions(LambdaQueryWrapper<CapitalInfo> wrapper,
CapitalInfoQueryDTO queryDTO) {
wrapper.eq(queryDTO.getCapitalState() != null,
CapitalInfo::getCapitalState, queryDTO.getCapitalState())
.like(StringUtils.isNotBlank(queryDTO.getCapitalName()),
CapitalInfo::getCapitalName, queryDTO.getCapitalName());
}
private void applySortRules(LambdaQueryWrapper<CapitalInfo> wrapper,
CapitalInfoQueryDTO queryDTO) {
// 明确的排序优先级
wrapper.orderByDesc(CapitalInfo::getCapitalYear) // 第一优先级:年份
.orderByAsc(CapitalInfo::getCapitalState) // 第二优先级:状态
.orderByDesc(CapitalInfo::getCreateTime) // 第三优先级:创建时间
.orderByAsc(CapitalInfo::getId); // 最后:ID保证稳定性
}
}
关键点总结:
-
优先使用
LambdaQueryWrapper,类型安全且重构友好 -
排序字段应遵循业务逻辑优先级
-
考虑添加数据库索引优化排序性能
-
对于大表查询,先筛选再排序
-
复杂的排序逻辑可以封装为独立的方法
更多推荐


所有评论(0)