7.7 KiB
MyBatis-Flex 的查询和分页
基础查询
在 MyBatis-Flex 的 BaseMapper 中,提供了如下的功能用于查询数据库的数据:
- selectOneById(id):根据主键 id 查询数据
- selectOneByMap(map):根据
map<字段名,值>组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。 - selectOneByCondition(condition):根据 condition 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。
- selectOneByQuery(query):根据 QueryWrapper 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。
- selectOneByQueryAs(query, asType):和
selectOneByQuery方法类似,但是在某些场景下,query可能包含了left join等多表查询,返回的数据和 entity 字段不一致时, 可以通过asType参数来指定接收的数据类型(通常是 dto、vo 等)。 - selectListByIds(idList):根据多个 id 查询,返回多条数据
- selectListByMap(map):根据
map<字段名,值>组成的条件查询数据。 - selectListByMap(map, count):根据
map<字段名,值>组成的条件查询数据,只取前 count 条。 - selectListByCondition(condition):根据 condition 组成的条件查询数据。
- selectListByCondition(condition, count):根据 condition 组成的条件查询数据,只取前 count 条。
- selectListByQuery(query): 根据 QueryWrapper 组成的条件查询数据。
- selectListByQueryAs(query, asType): 和
selectListByQuery方法类似,但是在某些场景下,query可能包含了left join等多表查询,返回的数据和 entity 字段不一致时, 可以通过asType参数来指定接收的数据类型(通常是 dto、vo 等)。 - selectAll:查询所有数据。
- selectObjectByQuery(query):查询只返回 1 列,并只有 1 条数据的场景。
- selectObjectListByQuery(query):查询只返回 1 列场景,比如
QueryWrapper.create().select(ACCOINT.ID).from(...)。 - selectObjectListByQueryAs(query, asType):对
selectObjectListByQuery进行封装,并转换为特定的类型。 - selectCountByCondition:根据 QueryWrapper 查询数据量。
- selectCountByQuery:根据 QueryWrapper 查询数据量。
多表查询(关联查询)
在 BaseMapper 中,提供了 selectOneByQueryAs、selectListByQueryAs 、paginateAs 等方法,用于处理关联查询的场景。
假设有 tb_account 用户表和 tb_article 文章表,他们的字段分别如下:
CREATE TABLE IF NOT EXISTS `tb_account`
(
`id` INTEGER PRIMARY KEY auto_increment,
`user_name` VARCHAR(100),
`age` Integer,
`birthday` DATETIME
);
CREATE TABLE IF NOT EXISTS `tb_article`
(
`id` INTEGER PRIMARY KEY auto_increment,
`account_id` Integer,
`title` VARCHAR(100),
`content` text
);
当我们进行关联查询时,可以通过如下 3 种方式进行。
方式 1
1、定义 ArticleDTO 类,ArticleDTO 里定义 tb_account 表的字段映射。
public class ArticleDTO {
private Long id;
private Long accountId;
private String title;
private String content;
//以下用户相关字段
private String userName;
private int age;
private Date birthday;
}
2、使用 QueryWrapper 构建 left join 查询,查询结果通过 ArticleDTO 类型接收。
QueryWrapper query = QueryWrapper.create()
.select(ARTICLE.ALL_COLUMNS)
.select(ACCOUNT.USER_NAME,ACCOUNT.AGE,ACCOUNT.BIRTHDAY)
.from(ARTICLE)
.leftJoin(ACCOUNT).on(ARTICLE.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(ACCOUNT.ID.ge(0));
List<ArticleDTO> results = mapper.selectListByQueryAs(query, ArticleDTO.class);
System.out.println(results);
方式 2
假设 ArticleDTO 定义的属性和 SQL 查询的字段不一致时,例如:
public class ArticleDTO {
private Long id;
private Long accountId;
private String title;
private String content;
//以下用户字段 和 用户表定义的列不一致,表定义的列为 user_name
private String authorName;
private int authorAge;
private Date birthday;
}
那么, QueryWrapper 需要添加 as,修改如下:
QueryWrapper query = QueryWrapper.create()
.select(ARTICLE.ALL_COLUMNS)
.select(ACCOUNT.USER_NAME.as(ArticleDTO::getAuthorName)
,ACCOUNT.AGE.as(ArticleDTO::getAuthorAge)
,ACCOUNT.BIRTHDAY
)
.from(ARTICLE)
.leftJoin(ACCOUNT).on(ARTICLE.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(ACCOUNT.ID.ge(0));
List<ArticleDTO> results = mapper.selectListByQueryAs(query, ArticleDTO.class);
System.out.println(results);
方式 3
1、定义 ArticleDTO 类, 在 ArticleDTO 定义 Account 实体类属性。 例如:
public class ArticleDTO {
private Long id;
private Long accountId;
private String title;
private String content;
//直接定义 Account 对象
private Account account;
}
2、使用 QueryWrapper 构建 left join 查询,查询结果通过 ArticleDTO 类型接收。
QueryWrapper query = QueryWrapper.create()
.select(ARTICLE.ALL_COLUMNS)
.select(ACCOUNT.USER_NAME,ACCOUNT.AGE,ACCOUNT.BIRTHDAY)
.from(ARTICLE)
.leftJoin(ACCOUNT).on(ARTICLE.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(ACCOUNT.ID.ge(0));
List<ArticleDTO> results = mapper.selectListByQueryAs(query, ArticleDTO.class);
System.out.println(results);
::: tip 方式 3 特别注意事项
- 1、在
ArticleDTO和Account这两个类中,如果他们有相同的字段,Account中的字段将不会被赋值(该字段为 null,常见的比如 id)。 - 2、假设在
ArticleDTO中有多个类似Account的对象,且他们有相同的字段(字段和ArticleDTO中的不相同),只有优先定义的属性被赋值。 :::
其他注意事项:
关联查询(
selectOneByQueryAs、selectListByQueryAs、paginateAs等方法)中的asType参数类型(比如:ArticleDTO), 一样支持使用@Column、@ColumnMask注解以及@Table的onInsert、onUpdate、onSet配置。
分页查询
在 MyBatis-Flex 的 BaseMapper 中,提供了如下的分页查询功能:
Page<T> paginate(int pageNumber, int pageSize, QueryWrapper queryWrapper);
Page<T> paginate(int pageNumber, int pageSize, int totalRow, QueryWrapper queryWrapper);
Page<T> paginate(int pageNumber, int pageSize, QueryCondition condition);
Page<T> paginate(int pageNumber, int pageSize, int totalRow, QueryCondition condition);
- pageNumber: 当前页码,从 1 开始
- pageSize: 每 1 页的数据量
- totalRow: 非必须值,若传入该值,mybatis-flex 则不再去查询总数据量(若传入小于 0 的数值,也会去查询总量)。
- queryWrapper: 查询条件
- QueryCondition: 查询条件
::: tip totalRow 的说明
在一般的分页场景中,只有第一页的时候有必要去查询数据总量,第二页以后是没必要的(因为第一页已经拿到总量了),因此,
第二页的时候,我们可以带入 totalRow,这样能提高程序的查询效率。
:::
paginate 的返回值为 Page 对象,Page 类的定义如下:
public class Page<T> implements Serializable {
private List<T> list; // list result of this page
private int pageNumber; // page number
private int pageSize; // result amount of this page
private long totalPage; // total page
private long totalRow; // total row
}