Skip to content

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 column

LambdaUpdateWrapper

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()))
);

参考资源

MIT License