pom
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
</dependency>
java
/**
1. 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
2. 3. 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力
4. 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力
*/
public interface BaseMapperX<T> extends MPJBaseMapper<T> {
default PageResult<T> selectPage(SortablePageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
return selectPage(pageParam, pageParam.getSortingFields(), queryWrapper);
}
default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
return selectPage(pageParam, null, queryWrapper);
}
default PageResult<T> selectPage(PageParam pageParam, Collection<SortingField> sortingFields, @Param("ew") Wrapper<T> queryWrapper) {
// 特殊:不分页,直接查询全部
if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageSize())) {
List<T> list = selectList(queryWrapper);
return new PageResult<>(list, (long) list.size());
}
// MyBatis Plus 查询
IPage<T> mpPage = MyBatisUtils.buildPage(pageParam, sortingFields);
selectPage(mpPage, queryWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
default <D> PageResult<D> selectJoinPage(PageParam pageParam, Class<D> clazz, MPJLambdaWrapper<T> lambdaWrapper) {
// 特殊:不分页,直接查询全部
if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageSize())) {
List<D> list = selectJoinList(clazz, lambdaWrapper);
return new PageResult<>(list, (long) list.size());
}
// MyBatis Plus Join 查询
IPage<D> mpPage = MyBatisUtils.buildPage(pageParam);
mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
default <DTO> PageResult<DTO> selectJoinPage(PageParam pageParam, Class<DTO> resultTypeClass, MPJBaseJoin<T> joinQueryWrapper) {
IPage<DTO> mpPage = MyBatisUtils.buildPage(pageParam);
selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
default T selectOne(String field, Object value) {
return selectOne(new QueryWrapper<T>().eq(field, value));
}
default T selectOne(SFunction<T, ?> field, Object value) {
return selectOne(new LambdaQueryWrapper<T>().eq(field, value));
}
default T selectOne(String field1, Object value1, String field2, Object value2) {
return selectOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
SFunction<T, ?> field3, Object value3) {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
.eq(field3, value3));
}
default Long selectCount() {
return selectCount(new QueryWrapper<>());
}
default Long selectCount(String field, Object value) {
return selectCount(new QueryWrapper<T>().eq(field, value));
}
default Long selectCount(SFunction<T, ?> field, Object value) {
return selectCount(new LambdaQueryWrapper<T>().eq(field, value));
}
default List<T> selectList() {
return selectList(new QueryWrapper<>());
}
default List<T> selectList(String field, Object value) {
return selectList(new QueryWrapper<T>().eq(field, value));
}
default List<T> selectList(SFunction<T, ?> field, Object value) {
return selectList(new LambdaQueryWrapper<T>().eq(field, value));
}
default List<T> selectList(String field, Collection<?> values) {
if (CollUtil.isEmpty(values)) {
return CollUtil.newArrayList();
}
return selectList(new QueryWrapper<T>().in(field, values));
}
default List<T> selectList(SFunction<T, ?> field, Collection<?> values) {
if (CollUtil.isEmpty(values)) {
return CollUtil.newArrayList();
}
return selectList(new LambdaQueryWrapper<T>().in(field, values));
}
default List<T> selectList(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
return selectList(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
/**
* 批量插入,适合大量数据插入
*
* @param entities 实体们
*/
default Boolean insertBatch(Collection<T> entities) {
// 特殊:SQL Server 批量插入后,获取 id 会报错,因此通过循环处理
DbType dbType = JdbcUtils.getDbType();
if (JdbcUtils.isSQLServer(dbType)) {
entities.forEach(this::insert);
return CollUtil.isNotEmpty(entities);
}
return Db.saveBatch(entities);
}
/**
* 批量插入,适合大量数据插入
*
* @param entities 实体们
* @param size 插入数量 Db.saveBatch 默认为 1000
*/
default Boolean insertBatch(Collection<T> entities, int size) {
// 特殊:SQL Server 批量插入后,获取 id 会报错,因此通过循环处理
DbType dbType = JdbcUtils.getDbType();
if (JdbcUtils.isSQLServer(dbType)) {
entities.forEach(this::insert);
return CollUtil.isNotEmpty(entities);
}
return Db.saveBatch(entities, size);
}
default int updateBatch(T update) {
return update(update, new QueryWrapper<>());
}
default Boolean updateBatch(Collection<T> entities) {
return Db.updateBatchById(entities);
}
default Boolean updateBatch(Collection<T> entities, int size) {
return Db.updateBatchById(entities, size);
}
default int delete(String field, String value) {
return delete(new QueryWrapper<T>().eq(field, value));
}
default int delete(SFunction<T, ?> field, Object value) {
return delete(new LambdaQueryWrapper<T>().eq(field, value));
}
}
一、核心定位
BaseMapperX 是 MyBatis Plus BaseMapper 的增强扩展接口,通过 统一封装高频操作 和 联表查询支持,解决以下痛点:
- 减少样板代码:内置分页、单字段查询等高频方法
- 类型安全:通过 Lambda 表达式避免字段名硬编码
- 多表联查简化:集成 MyBatis Plus Join 能力
- 数据库兼容:处理 SQL Server 等特殊批量插入场景
二、关键增强功能
1. 分页查询统一封装
// 原生 MyBatis Plus 分页
IPage<UserDO> page = new Page<>(1, 10);
mapper.selectPage(page, queryWrapper);
PageResult<UserDO> result = new PageResult<>(page.getRecords(), page.getTotal());
// 使用 BaseMapperX 简化后
PageResult<UserDO> result = mapper.selectPage(pageParam, queryWrapper);
2. 联表分页查询
PageResult<UserDeptVO> result = mapper.selectJoinPage(
pageParam, UserDeptVO.class,
new MPJLambdaWrapperX<UserDO>()
.selectAll(UserDO.class)
.leftJoin(DepartmentDO.class, ...)
);
3. 高频单表操作
// 根据单个字段查询
UserDO user = mapper.selectOne(UserDO::getUsername, "yudaoyuanma");
// 根据多个字段查询
UserDO user = mapper.selectOne(
UserDO::getUsername, "yudaoyuanma",
UserDO::getStatus, 0
);
// 批量插入(自动处理 SQL Server 兼容)
mapper.insertBatch(users);
三、设计模式解析
1. 模板方法模式(Template Method)
- 体现:selectPage 方法统一分页处理流程
public default PageResult<T> selectPage(PageParam pageParam, Wrapper<T> queryWrapper) {
// 1. 构建分页参数(模板步骤)
IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
// 2. 执行查询(具体实现由 MyBatis Plus 提供)
selectPage(mpPage, queryWrapper);
// 3. 结果转换(模板步骤)
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
2. 门面模式(Facade)
- 体现:对复杂联表查询进行高层抽象
public default <D> PageResult<D> selectJoinPage(...) {
// 隐藏联表查询的复杂性
IPage<D> mpPage = MyBatisUtils.buildPage(pageParam);
selectJoinPage(mpPage, clazz, lambdaWrapper);
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
3. 策略模式(Strategy)
- 体现:根据数据库类型切换批量插入策略
default Boolean insertBatch(Collection<T> entities) {
if (JdbcUtils.isSQLServer()) { // SQL Server 策略
entities.forEach(this::insert);
} else { // 通用策略
Db.saveBatch(entities);
}
return true;
}
四、与原生 API 对比
功能 | MyBatis Plus BaseMapper | BaseMapperX |
---|---|---|
分页封装 | 需手动处理 IPage 对象 | 直接返回 PageResult 统一结构 |
联表查询 | 不支持 | 支持连表分页查询与 VO 映射 |
字段条件方法 | 需手动写 QueryWrapper | 提供 selectOne(field, value) 等快捷方法 |
批量插入兼容性 | 需自行处理数据库差异 | 内置 SQL Server 特殊逻辑 |