mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-06 16:48:24 +08:00
commit
4b8f64685c
@ -132,14 +132,48 @@ processor.mappersPackage = com.your-package
|
|||||||
processor.baseMapperClass=com.domain.mapper.MyBaseMapper
|
processor.baseMapperClass=com.domain.mapper.MyBaseMapper
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 实体类不在一个包中
|
||||||
|
|
||||||
|
有时候可能会遇到实体类不在同一个包中的情况,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
com.example.entityPackage1
|
||||||
|
└─ Entity1
|
||||||
|
com.example.entityPackage2
|
||||||
|
└─ Entity2
|
||||||
|
```
|
||||||
|
|
||||||
|
此时的辅助类会生成在对应的包下,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
com.example.entityPackage1.table
|
||||||
|
└─ Entity1TableDef
|
||||||
|
com.example.entityPackage2.table
|
||||||
|
└─ Entity2TableDef
|
||||||
|
```
|
||||||
|
|
||||||
|
但是,如果您设置了 `processor.allInTables=true` 的话,`Tables` 文件将会生成在最后一个包中,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
com.example.entityPackage2.table
|
||||||
|
└─ Tables
|
||||||
|
```
|
||||||
|
|
||||||
|
所以,如果您的实体类在多个包中,又指定了 `processor.allInTables=true` 选项,推荐设置 `Tables` 文件的位置,例如:
|
||||||
|
|
||||||
|
```properties
|
||||||
|
processor.allInTables=true
|
||||||
|
processor.tablesPackage=com.example.entity.table
|
||||||
|
```
|
||||||
|
|
||||||
## 和 Lombok、Mapstruct 整合
|
## 和 Lombok、Mapstruct 整合
|
||||||
|
|
||||||
在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们再 pom.xml 添加 `annotationProcessorPaths` 配置,
|
在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们再
|
||||||
|
pom.xml 添加 `annotationProcessorPaths` 配置,
|
||||||
此时,我们也需要把 MyBatis-Flex 的 annotation 添加到 `annotationProcessorPaths` 配置里去,如下图所示:
|
此时,我们也需要把 MyBatis-Flex 的 annotation 添加到 `annotationProcessorPaths` 配置里去,如下图所示:
|
||||||
|
|
||||||
```xml 24,25,26,27,28
|
```xml 24,25,26,27,28
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
|||||||
@ -20,7 +20,10 @@ import com.mybatisflex.core.field.FieldQueryBuilder;
|
|||||||
import com.mybatisflex.core.mybatis.MappedStatementTypes;
|
import com.mybatisflex.core.mybatis.MappedStatementTypes;
|
||||||
import com.mybatisflex.core.paginate.Page;
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.provider.EntitySqlProvider;
|
import com.mybatisflex.core.provider.EntitySqlProvider;
|
||||||
import com.mybatisflex.core.query.*;
|
import com.mybatisflex.core.query.CPI;
|
||||||
|
import com.mybatisflex.core.query.QueryColumn;
|
||||||
|
import com.mybatisflex.core.query.QueryCondition;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.core.table.TableInfo;
|
import com.mybatisflex.core.table.TableInfo;
|
||||||
import com.mybatisflex.core.table.TableInfoFactory;
|
import com.mybatisflex.core.table.TableInfoFactory;
|
||||||
import com.mybatisflex.core.util.*;
|
import com.mybatisflex.core.util.*;
|
||||||
@ -667,47 +670,43 @@ public interface BaseMapper<T> {
|
|||||||
|
|
||||||
|
|
||||||
default <R> Page<R> paginateAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {
|
default <R> Page<R> paginateAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {
|
||||||
List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper);
|
try {
|
||||||
List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper);
|
// 只有 totalRow 小于 0 的时候才会去查询总量
|
||||||
List<Join> joins = CPI.getJoins(queryWrapper);
|
// 这样方便用户做总数缓存,而非每次都要去查询总量
|
||||||
// 只有 totalRow 小于 0 的时候才会去查询总量
|
// 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的
|
||||||
// 这样方便用户做总数缓存,而非每次都要去查询总量
|
if (page.getTotalRow() < 0) {
|
||||||
// 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的
|
QueryWrapper countQueryWrapper;
|
||||||
if (page.getTotalRow() < 0) {
|
if (page.isOptimizeCountSql()) {
|
||||||
QueryWrapper countQueryWrapper = MapperUtil.optimizeCountQueryWrapper(queryWrapper);
|
countQueryWrapper = MapperUtil.optimizeCountQueryWrapper(queryWrapper);
|
||||||
long count = selectCountByQuery(countQueryWrapper);
|
} else {
|
||||||
page.setTotalRow(count);
|
countQueryWrapper = MapperUtil.rawCountQueryWrapper(queryWrapper);
|
||||||
}
|
}
|
||||||
|
page.setTotalRow(selectCountByQuery(countQueryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page.isEmpty()) {
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryWrapper.limit(page.getOffset(), page.getPageSize());
|
||||||
|
|
||||||
|
List<R> records;
|
||||||
|
if (asType != null) {
|
||||||
|
records = selectListByQueryAs(queryWrapper, asType);
|
||||||
|
} else {
|
||||||
|
records = (List<R>) selectListByQuery(queryWrapper);
|
||||||
|
}
|
||||||
|
MapperUtil.queryFields(this, records, consumers);
|
||||||
|
page.setRecords(records);
|
||||||
|
|
||||||
if (page.isEmpty()) {
|
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 将之前设置的 limit 清除掉
|
||||||
|
// 保险起见把重置代码放到 finally 代码块中
|
||||||
|
CPI.setLimitRows(queryWrapper, null);
|
||||||
|
CPI.setLimitOffset(queryWrapper, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//重置 selectColumns
|
|
||||||
CPI.setSelectColumns(queryWrapper, selectColumns);
|
|
||||||
//重置 orderBys
|
|
||||||
CPI.setOrderBys(queryWrapper, orderBys);
|
|
||||||
//重置 join
|
|
||||||
CPI.setJoins(queryWrapper, joins);
|
|
||||||
|
|
||||||
int offset = page.getPageSize() * (page.getPageNumber() - 1);
|
|
||||||
queryWrapper.limit(offset, page.getPageSize());
|
|
||||||
|
|
||||||
if (asType != null) {
|
|
||||||
List<R> records = selectListByQueryAs(queryWrapper, asType);
|
|
||||||
MapperUtil.queryFields(this, records, consumers);
|
|
||||||
page.setRecords(records);
|
|
||||||
} else {
|
|
||||||
List<R> records = (List<R>) selectListByQuery(queryWrapper);
|
|
||||||
MapperUtil.queryFields(this, records, consumers);
|
|
||||||
page.setRecords(records);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将之前设置的 limit 清除掉
|
|
||||||
CPI.setLimitRows(queryWrapper, null);
|
|
||||||
CPI.setLimitOffset(queryWrapper, null);
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mybatisflex.core.paginate;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页接口。
|
||||||
|
*
|
||||||
|
* @param <T> 数据类型
|
||||||
|
* @author 王帅
|
||||||
|
* @since 2023-06-18
|
||||||
|
*/
|
||||||
|
public interface IPage<T> extends Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前页码。
|
||||||
|
*
|
||||||
|
* @return 页码
|
||||||
|
*/
|
||||||
|
int getPageNumber();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前页码。
|
||||||
|
*
|
||||||
|
* @param pageNumber 页码
|
||||||
|
*/
|
||||||
|
void setPageNumber(int pageNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前每页数据数量。
|
||||||
|
*
|
||||||
|
* @return 每页数据数量
|
||||||
|
*/
|
||||||
|
int getPageSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前每页数据数量。
|
||||||
|
*
|
||||||
|
* @param pageSize 每页数据数量
|
||||||
|
*/
|
||||||
|
void setPageSize(int pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据总数。
|
||||||
|
*
|
||||||
|
* @return 数据总数
|
||||||
|
*/
|
||||||
|
long getTotalRow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置数据总数。
|
||||||
|
*
|
||||||
|
* @param totalRow 数据总数
|
||||||
|
*/
|
||||||
|
void setTotalRow(long totalRow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前页的数据。
|
||||||
|
*
|
||||||
|
* @return 当前页的数据
|
||||||
|
*/
|
||||||
|
List<T> getRecords();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前页的数据。
|
||||||
|
*
|
||||||
|
* @param records 当前页的数据
|
||||||
|
*/
|
||||||
|
void setRecords(List<T> records);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前分页偏移量。
|
||||||
|
*
|
||||||
|
* @return 偏移量
|
||||||
|
*/
|
||||||
|
default int getOffset() {
|
||||||
|
return getPageSize() * (getPageNumber() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否自动优化 COUNT 查询语句(默认优化)。
|
||||||
|
*
|
||||||
|
* @return {@code true} 优化,{@code false} 不优化
|
||||||
|
*/
|
||||||
|
default boolean isOptimizeCountSql() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否自动优化 COUNT 查询语句。
|
||||||
|
*
|
||||||
|
* @param optimizeCountSql 是否优化
|
||||||
|
*/
|
||||||
|
default void setOptimizeCountSql(boolean optimizeCountSql) {
|
||||||
|
// 默认总是优化
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取总页数。
|
||||||
|
*
|
||||||
|
* @return 总页数
|
||||||
|
*/
|
||||||
|
default long getTotalPage() {
|
||||||
|
// 实时计算总页数
|
||||||
|
int pageSize = getPageSize();
|
||||||
|
if (pageSize == 0) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
long totalRow = getTotalRow();
|
||||||
|
long totalPage = totalRow / pageSize;
|
||||||
|
if (totalRow % pageSize != 0) {
|
||||||
|
totalPage++;
|
||||||
|
}
|
||||||
|
return totalPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置总页数。
|
||||||
|
*
|
||||||
|
* @param totalPage 总页数
|
||||||
|
*/
|
||||||
|
default void setTotalPage(long totalPage) {
|
||||||
|
// 总页数是实时计算的,所以这里设置了也没用。
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在上一页。
|
||||||
|
*
|
||||||
|
* @return {@code true} 存在上一页,{@code false} 不存在上一页
|
||||||
|
*/
|
||||||
|
default boolean hasPrevious() {
|
||||||
|
return getPageNumber() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在下一页。
|
||||||
|
*
|
||||||
|
* @return {@code true} 存在下一页,{@code false} 不存在下一页
|
||||||
|
*/
|
||||||
|
default boolean hasNext() {
|
||||||
|
return getPageNumber() < getTotalPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页是否为空。
|
||||||
|
*
|
||||||
|
* @return {@code true} 空页,{@code false} 非空页
|
||||||
|
*/
|
||||||
|
default boolean isEmpty() {
|
||||||
|
return getTotalRow() == 0 || getPageNumber() > getTotalPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -15,13 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.mybatisflex.core.paginate;
|
package com.mybatisflex.core.paginate;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class Page<T> implements Serializable {
|
public class Page<T> implements IPage<T> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public static final int INIT_VALUE = -1;
|
public static final int INIT_VALUE = -1;
|
||||||
@ -32,6 +31,8 @@ public class Page<T> implements Serializable {
|
|||||||
private long totalPage = INIT_VALUE;
|
private long totalPage = INIT_VALUE;
|
||||||
private long totalRow = INIT_VALUE;
|
private long totalRow = INIT_VALUE;
|
||||||
|
|
||||||
|
private boolean optimizeCountSql = true;
|
||||||
|
|
||||||
public static <T> Page<T> of(int pageNumber, int pageSize) {
|
public static <T> Page<T> of(int pageNumber, int pageSize) {
|
||||||
return new Page<>(pageNumber, pageSize);
|
return new Page<>(pageNumber, pageSize);
|
||||||
}
|
}
|
||||||
@ -64,10 +65,22 @@ public class Page<T> implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOptimizeCountSql() {
|
||||||
|
return optimizeCountSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOptimizeCountSql(boolean optimizeCountSql) {
|
||||||
|
this.optimizeCountSql = optimizeCountSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<T> getRecords() {
|
public List<T> getRecords() {
|
||||||
return records;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setRecords(List<T> records) {
|
public void setRecords(List<T> records) {
|
||||||
if (records == null) {
|
if (records == null) {
|
||||||
records = Collections.emptyList();
|
records = Collections.emptyList();
|
||||||
@ -75,10 +88,12 @@ public class Page<T> implements Serializable {
|
|||||||
this.records = records;
|
this.records = records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPageNumber() {
|
public int getPageNumber() {
|
||||||
return pageNumber;
|
return pageNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setPageNumber(int pageNumber) {
|
public void setPageNumber(int pageNumber) {
|
||||||
if (pageNumber < 1) {
|
if (pageNumber < 1) {
|
||||||
throw new IllegalArgumentException("pageNumber must greater than or equal 1,current value is: " + pageNumber);
|
throw new IllegalArgumentException("pageNumber must greater than or equal 1,current value is: " + pageNumber);
|
||||||
@ -87,10 +102,12 @@ public class Page<T> implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPageSize() {
|
public int getPageSize() {
|
||||||
return pageSize;
|
return pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setPageSize(int pageSize) {
|
public void setPageSize(int pageSize) {
|
||||||
if (pageSize < 0) {
|
if (pageSize < 0) {
|
||||||
throw new IllegalArgumentException("pageSize must greater than or equal 0,current value is: " + pageSize);
|
throw new IllegalArgumentException("pageSize must greater than or equal 0,current value is: " + pageSize);
|
||||||
@ -99,18 +116,22 @@ public class Page<T> implements Serializable {
|
|||||||
this.calcTotalPage();
|
this.calcTotalPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getTotalPage() {
|
public long getTotalPage() {
|
||||||
return totalPage;
|
return totalPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setTotalPage(long totalPage) {
|
public void setTotalPage(long totalPage) {
|
||||||
this.totalPage = totalPage;
|
this.totalPage = totalPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getTotalRow() {
|
public long getTotalRow() {
|
||||||
return totalRow;
|
return totalRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setTotalRow(long totalRow) {
|
public void setTotalRow(long totalRow) {
|
||||||
this.totalRow = totalRow;
|
this.totalRow = totalRow;
|
||||||
this.calcTotalPage();
|
this.calcTotalPage();
|
||||||
@ -127,10 +148,12 @@ public class Page<T> implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return getTotalRow() == 0 || getPageNumber() > getTotalPage();
|
return getTotalRow() == 0 || getPageNumber() > getTotalPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return getTotalPage() != 0 && getPageNumber() < getTotalPage();
|
return getTotalPage() != 0 && getPageNumber() < getTotalPage();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,9 @@ import com.mybatisflex.core.FlexConsts;
|
|||||||
import com.mybatisflex.core.exception.FlexExceptions;
|
import com.mybatisflex.core.exception.FlexExceptions;
|
||||||
import com.mybatisflex.core.paginate.Page;
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.provider.RowSqlProvider;
|
import com.mybatisflex.core.provider.RowSqlProvider;
|
||||||
import com.mybatisflex.core.query.*;
|
import com.mybatisflex.core.query.CPI;
|
||||||
|
import com.mybatisflex.core.query.QueryColumn;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.core.util.CollectionUtil;
|
import com.mybatisflex.core.util.CollectionUtil;
|
||||||
import com.mybatisflex.core.util.MapperUtil;
|
import com.mybatisflex.core.util.MapperUtil;
|
||||||
import com.mybatisflex.core.util.StringUtil;
|
import com.mybatisflex.core.util.StringUtil;
|
||||||
@ -431,47 +433,39 @@ public interface RowMapper {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
default Page<Row> paginate(String schema, String tableName, Page<Row> page, QueryWrapper queryWrapper) {
|
default Page<Row> paginate(String schema, String tableName, Page<Row> page, QueryWrapper queryWrapper) {
|
||||||
|
try {
|
||||||
|
CPI.setFromIfNecessary(queryWrapper, schema, tableName);
|
||||||
|
|
||||||
CPI.setFromIfNecessary(queryWrapper, schema, tableName);
|
// 只有 totalRow 小于 0 的时候才会去查询总量
|
||||||
|
// 这样方便用户做总数缓存,而非每次都要去查询总量
|
||||||
|
// 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的
|
||||||
|
if (page.getTotalRow() < 0) {
|
||||||
|
QueryWrapper countQueryWrapper;
|
||||||
|
if (page.isOptimizeCountSql()) {
|
||||||
|
countQueryWrapper = MapperUtil.optimizeCountQueryWrapper(queryWrapper);
|
||||||
|
} else {
|
||||||
|
countQueryWrapper = MapperUtil.rawCountQueryWrapper(queryWrapper);
|
||||||
|
}
|
||||||
|
page.setTotalRow(selectCountByQuery(schema, tableName, countQueryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper);
|
if (page.isEmpty()) {
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper);
|
queryWrapper.limit(page.getOffset(), page.getPageSize());
|
||||||
|
|
||||||
List<Join> joins = CPI.getJoins(queryWrapper);
|
page.setRecords(selectListByQuery(schema, tableName, queryWrapper));
|
||||||
|
|
||||||
// 只有 totalRow 小于 0 的时候才会去查询总量
|
|
||||||
// 这样方便用户做总数缓存,而非每次都要去查询总量
|
|
||||||
// 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的
|
|
||||||
if (page.getTotalRow() < 0) {
|
|
||||||
QueryWrapper countQueryWrapper = MapperUtil.optimizeCountQueryWrapper(queryWrapper);
|
|
||||||
long count = selectCountByQuery(schema, tableName, countQueryWrapper);
|
|
||||||
page.setTotalRow(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (page.isEmpty()) {
|
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 将之前设置的 limit 清除掉
|
||||||
|
// 保险起见把重置代码放到 finally 代码块中
|
||||||
|
CPI.setLimitRows(queryWrapper, null);
|
||||||
|
CPI.setLimitOffset(queryWrapper, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//重置 selectColumns
|
|
||||||
CPI.setSelectColumns(queryWrapper, selectColumns);
|
|
||||||
//重置 orderBys
|
|
||||||
CPI.setOrderBys(queryWrapper, orderBys);
|
|
||||||
//重置 join
|
|
||||||
CPI.setJoins(queryWrapper, joins);
|
|
||||||
|
|
||||||
int offset = page.getPageSize() * (page.getPageNumber() - 1);
|
|
||||||
queryWrapper.limit(offset, page.getPageSize());
|
|
||||||
|
|
||||||
List<Row> records = selectListByQuery(schema, tableName, queryWrapper);
|
|
||||||
page.setRecords(records);
|
|
||||||
|
|
||||||
// 将之前设置的 limit 清除掉
|
|
||||||
CPI.setLimitRows(queryWrapper, null);
|
|
||||||
CPI.setLimitOffset(queryWrapper, null);
|
|
||||||
|
|
||||||
return page;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ public class MapperUtil {
|
|||||||
*
|
*
|
||||||
* <p><pre>
|
* <p><pre>
|
||||||
* {@code
|
* {@code
|
||||||
* SELECT COUNT(*) AS `total` FROM ( ...用户构建的 SQL 语句... );
|
* SELECT COUNT(*) AS `total` FROM ( ...用户构建的 SQL 语句... ) AS `t`;
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
@ -58,22 +58,25 @@ public class MapperUtil {
|
|||||||
* 优化 COUNT 查询语句。
|
* 优化 COUNT 查询语句。
|
||||||
*/
|
*/
|
||||||
public static QueryWrapper optimizeCountQueryWrapper(QueryWrapper queryWrapper) {
|
public static QueryWrapper optimizeCountQueryWrapper(QueryWrapper queryWrapper) {
|
||||||
List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper);
|
// 对克隆对象进行操作,不影响原来的 QueryWrapper 对象
|
||||||
List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper);
|
QueryWrapper clone = queryWrapper.clone();
|
||||||
|
// 将最后面的 order by 移除掉
|
||||||
|
CPI.setOrderBys(clone, null);
|
||||||
|
// 获取查询列和分组列,用于判断是否进行优化
|
||||||
|
List<QueryColumn> selectColumns = CPI.getSelectColumns(clone);
|
||||||
|
List<QueryColumn> groupByColumns = CPI.getGroupByColumns(clone);
|
||||||
// 如果有 distinct 语句或者 group by 语句则不优化
|
// 如果有 distinct 语句或者 group by 语句则不优化
|
||||||
// 这种一旦优化了就会造成 count 语句查询出来的值不对
|
// 这种一旦优化了就会造成 count 语句查询出来的值不对
|
||||||
if (hasDistinct(selectColumns) || hasGroupBy(groupByColumns)) {
|
if (hasDistinct(selectColumns) || hasGroupBy(groupByColumns)) {
|
||||||
return rawCountQueryWrapper(queryWrapper);
|
return rawCountQueryWrapper(clone);
|
||||||
}
|
}
|
||||||
// 判断能不能清除 join 语句
|
// 判断能不能清除 join 语句
|
||||||
if (canClearJoins(queryWrapper)) {
|
if (canClearJoins(clone)) {
|
||||||
CPI.setJoins(queryWrapper, null);
|
CPI.setJoins(clone, null);
|
||||||
}
|
}
|
||||||
// 最后将最后面的 order by 移除掉
|
// 将 select 里面的列换成 COUNT(*) AS `total`
|
||||||
// 将 select 里面的列换成 COUNT(*) AS `total` 就好了
|
CPI.setSelectColumns(clone, Collections.singletonList(count().as("total")));
|
||||||
CPI.setOrderBys(queryWrapper, null);
|
return clone;
|
||||||
CPI.setSelectColumns(queryWrapper, Collections.singletonList(count().as("total")));
|
|
||||||
return queryWrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasDistinct(List<QueryColumn> selectColumns) {
|
private static boolean hasDistinct(List<QueryColumn> selectColumns) {
|
||||||
|
|||||||
@ -19,6 +19,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
|||||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||||
import org.springframework.context.annotation.ConditionContext;
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.core.env.*;
|
import org.springframework.core.env.*;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ import java.util.Iterator;
|
|||||||
@Conditional(ConditionalOnMybatisFlexDatasource.OnMybatisFlexDataSourceCondition.class)
|
@Conditional(ConditionalOnMybatisFlexDatasource.OnMybatisFlexDataSourceCondition.class)
|
||||||
public @interface ConditionalOnMybatisFlexDatasource {
|
public @interface ConditionalOnMybatisFlexDatasource {
|
||||||
|
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
|
||||||
class OnMybatisFlexDataSourceCondition extends SpringBootCondition {
|
class OnMybatisFlexDataSourceCondition extends SpringBootCondition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -44,8 +47,8 @@ public @interface ConditionalOnMybatisFlexDatasource {
|
|||||||
Iterator<PropertySource<?>> it = propertySources.stream().iterator();
|
Iterator<PropertySource<?>> it = propertySources.stream().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
PropertySource<?> ps = it.next();
|
PropertySource<?> ps = it.next();
|
||||||
if (ps instanceof MapPropertySource) {
|
if (ps instanceof EnumerablePropertySource) {
|
||||||
for (String propertyName : ((MapPropertySource) ps).getSource().keySet()) {
|
for (String propertyName : ((EnumerablePropertySource<?>) ps).getPropertyNames()) {
|
||||||
if (propertyName.startsWith("mybatis-flex.datasource.")) {
|
if (propertyName.startsWith("mybatis-flex.datasource.")) {
|
||||||
return ConditionOutcome.match();
|
return ConditionOutcome.match();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,10 +143,11 @@ class UserMapperTest {
|
|||||||
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.USER_ID.eq(USER.USER_ID))
|
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.USER_ID.eq(USER.USER_ID))
|
||||||
.leftJoin(ROLE).as("r").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID));
|
.leftJoin(ROLE).as("r").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID));
|
||||||
System.err.println(queryWrapper.toSQL());
|
System.err.println(queryWrapper.toSQL());
|
||||||
Page<UserVO> page;
|
Page<UserVO> page = Page.of(1, 1);
|
||||||
|
page.setOptimizeCountSql(false);
|
||||||
int pageNumber = 0;
|
int pageNumber = 0;
|
||||||
do {
|
do {
|
||||||
page = Page.of(++pageNumber, 1);
|
page.setPageNumber(page.getPageNumber() + 1);
|
||||||
page = userMapper.paginateAs(page, queryWrapper, UserVO.class);
|
page = userMapper.paginateAs(page, queryWrapper, UserVO.class);
|
||||||
System.err.println(page);
|
System.err.println(page);
|
||||||
} while (page.hasNext());
|
} while (page.hasNext());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user