MyBatis-Plus 使用指南
本文档详细介绍 MyBatis-Plus 的使用方法。
简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
- 无侵入:只做增强不做改变
- 损耗小:启动即会自动注入基本 CRUD
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service
- 支持 Lambda:类型安全,避免字段写错
- 支持主键自动生成:支持多种主键策略
- 内置分页插件:基于 MyBatis 物理分页
实体类配置
基础实体类
java
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String realName;
private String email;
private String phone;
private Long deptId;
private Integer status;
@TableField(exist = false)
private String deptName;
}公共字段基类
java
@Data
public class BaseEntity implements Serializable {
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateBy;
}Mapper 层
创建 Mapper
java
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
// 继承 BaseMapper 后自动拥有 CRUD 方法
}BaseMapper 提供的方法
java
// 插入
int insert(T entity);
// 删除
int deleteById(Serializable id);
int deleteByMap(Map<String, Object> columnMap);
int delete(Wrapper<T> wrapper);
int deleteBatchIds(Collection<? extends Serializable> idList);
// 更新
int updateById(T entity);
int update(T entity, Wrapper<T> updateWrapper);
// 查询
T selectById(Serializable id);
List<T> selectBatchIds(Collection<? extends Serializable> idList);
List<T> selectByMap(Map<String, Object> columnMap);
T selectOne(Wrapper<T> queryWrapper);
Long selectCount(Wrapper<T> queryWrapper);
List<T> selectList(Wrapper<T> queryWrapper);
Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper);Service 层
创建 Service
java
public interface SysUserService extends IService<SysUser> {
void createUser(UserDTO dto);
}创建 Service 实现类
java
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
implements SysUserService {
@Override
public void createUser(UserDTO dto) {
SysUser user = new SysUser();
user.setUsername(dto.getUsername());
user.setPassword(dto.getPassword());
this.save(user);
}
}IService 提供的方法
java
// 保存
boolean save(T entity);
boolean saveBatch(Collection<T> entityList);
boolean saveOrUpdate(T entity);
// 删除
boolean removeById(Serializable id);
boolean removeByMap(Map<String, Object> columnMap);
boolean remove(Wrapper<T> queryWrapper);
boolean removeByIds(Collection<? extends Serializable> idList);
// 更新
boolean updateById(T entity);
boolean update(Wrapper<T> updateWrapper);
boolean update(T entity, Wrapper<T> updateWrapper);
boolean updateBatchById(Collection<T> entityList);
// 查询
T getById(Serializable id);
T getOne(Wrapper<T> queryWrapper);
long count();
long count(Wrapper<T> queryWrapper);
List<T> list();
List<T> list(Wrapper<T> queryWrapper);
Collection<T> listByIds(Collection<? extends Serializable> idList);
Page<T> page(Page<T> page);
Page<T> page(Page<T> page, Wrapper<T> queryWrapper);条件构造器
LambdaQueryWrapper
java
// 基础查询
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getUsername, "admin")
.eq(SysUser::getStatus, 1);
List<SysUser> users = userMapper.selectList(wrapper);
// 模糊查询
wrapper.like(SysUser::getUsername, "test")
.likeRight(SysUser::getPhone, "138");
// 范围查询
wrapper.between(SysUser::getCreateTime, startTime, endTime)
.in(SysUser::getStatus, Arrays.asList(1, 2));
// 排序
wrapper.orderByDesc(SysUser::getCreateTime)
.orderByAsc(SysUser::getUsername);
// 动态条件
wrapper.eq(StrUtil.isNotBlank(username), SysUser::getUsername, username)
.eq(status != null, SysUser::getStatus, status);常用条件方法
java
// 等于
eq(column, value) // =
ne(column, value) // !=
// 大于/小于
gt(column, value) // >
ge(column, value) // >=
lt(column, value) // <
le(column, value) // <=
// 模糊查询
like(column, value) // LIKE '%value%'
likeLeft(column, value) // LIKE '%value'
likeRight(column, value) // LIKE 'value%'
// 范围查询
between(column, val1, val2) // BETWEEN val1 AND val2
in(column, collection) // IN (collection)
// 空值判断
isNull(column) // IS NULL
isNotNull(column) // IS NOT NULL
// 排序
orderByAsc(column) // ORDER BY column ASC
orderByDesc(column) // ORDER BY column DESC
// 分组
groupBy(column) // GROUP BY columnLambdaUpdateWrapper
java
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(SysUser::getStatus, 0)
.set(SysUser::getUpdateTime, LocalDateTime.now())
.eq(SysUser::getId, userId);
userMapper.update(null, wrapper);分页查询
配置分页插件
java
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}使用分页
java
// Mapper 层分页
Page<SysUser> page = new Page<>(1, 10);
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getStatus, 1)
.orderByDesc(SysUser::getCreateTime);
Page<SysUser> result = userMapper.selectPage(page, wrapper);
List<SysUser> records = result.getRecords();
long total = result.getTotal();
// Service 层分页
public PageResult<UserInfoVO> pageList(UserQuery query) {
Page<SysUser> page = new Page<>(query.getPage(), query.getPageSize());
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(query.getUsername()),
SysUser::getUsername, query.getUsername())
.eq(query.getStatus() != null,
SysUser::getStatus, query.getStatus())
.orderByDesc(SysUser::getCreateTime);
Page<SysUser> result = this.page(page, wrapper);
List<UserInfoVO> voList = result.getRecords().stream()
.map(user -> BeanUtil.copyProperties(user, UserInfoVO.class))
.collect(Collectors.toList());
return PageResult.of(voList, result.getTotal(),
query.getPage(), query.getPageSize());
}常用注解
@TableName
java
@TableName("sys_user")
public class SysUser {
// ...
}@TableId
java
public class SysUser {
@TableId(type = IdType.AUTO)
private Long id;
}主键策略:
IdType.AUTO:数据库自增IdType.INPUT:手动输入IdType.ASSIGN_ID:雪花算法IdType.ASSIGN_UUID:UUID
@TableField
java
public class SysUser {
// 字段名映射
@TableField("user_name")
private String username;
// 不映射到数据库
@TableField(exist = false)
private String deptName;
// 自动填充
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}@TableLogic
java
public class SysUser {
@TableLogic
private Integer deleted; // 0-未删除,1-已删除
}配置:
yaml
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0自动填充
java
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
Long userId = LoginUserUtils.getUserId();
if (userId != null) {
this.strictInsertFill(metaObject, "createBy", Long.class, userId);
}
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
Long userId = LoginUserUtils.getUserId();
if (userId != null) {
this.strictUpdateFill(metaObject, "updateBy", Long.class, userId);
}
}
}最佳实践
1. 使用 Lambda 避免字段名错误
java
// ✅ 推荐
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getUsername, "admin");
// ❌ 不推荐
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
wrapper.eq("username", "admin");2. 动态条件查询
java
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(query.getUsername()),
SysUser::getUsername, query.getUsername())
.eq(query.getStatus() != null,
SysUser::getStatus, query.getStatus());3. 批量操作
java
// ✅ 推荐:批量插入
userService.saveBatch(userList);
// ❌ 不推荐:循环单条插入
for (SysUser user : userList) {
userService.save(user);
}4. 使用事务
java
@Transactional(rollbackFor = Exception.class)
public void createUser(UserDTO dto) {
SysUser user = new SysUser();
user.setUsername(dto.getUsername());
this.save(user);
saveUserRoles(user.getId(), dto.getRoleIds());
}5. 只查询需要的字段
java
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SysUser::getId, SysUser::getUsername, SysUser::getRealName)
.eq(SysUser::getStatus, 1);6. 避免 N+1 查询
java
// ❌ 不推荐
List<SysUser> users = userMapper.selectList(null);
for (SysUser user : users) {
SysDept dept = deptMapper.selectById(user.getDeptId());
user.setDeptName(dept.getName());
}
// ✅ 推荐
List<SysUser> users = userMapper.selectList(null);
List<Long> deptIds = users.stream()
.map(SysUser::getDeptId)
.distinct()
.collect(Collectors.toList());
List<SysDept> depts = deptMapper.selectBatchIds(deptIds);
Map<Long, String> deptMap = depts.stream()
.collect(Collectors.toMap(SysDept::getId, SysDept::getName));
users.forEach(user ->
user.setDeptName(deptMap.get(user.getDeptId()))
);