MyBatis-Plus(简称 MP)是在 MyBatis 基础上的增强工具,Mapper Interface 是 MP 实现数据库操作的核心组件,它无需编写 XML 映射文件,通过继承通用接口即可直接使用单表的增删改查、分页、条件构造等基础功能,大幅简化开发流程。
MP 中的 Mapper Interface 是数据访问层(DAO)的接口定义,继承 MP 提供的 BaseMapper<T> 通用接口后,无需实现类,即可自动获得单表的全套 CRUD 操作能力。
替代传统 MyBatis 中手动编写的 Mapper 接口 + XML 映射文件
直接调用内置方法完成单表操作,无需重复编写 SQL
支持自定义方法扩展,兼容原生 MyBatis 语法
结合条件构造器,实现复杂条件查询
实体类对应数据库表,通过 MP 注解完成映射:
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data // Lombok 简化 getter/setter
@TableName("t_user") // 对应数据库表名(类名与表名一致可省略)
public class User {
// 主键自增,对应数据库主键字段
@TableId(type = IdType.AUTO)
private Long id;
private String username; // 字段名与属性名一致,自动映射
private Integer age;
private String email;
}创建接口并继承 BaseMapper<T>,泛型指定对应实体类:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
// @Mapper:让 Spring 扫描到该接口,生成代理对象
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 无需编写任何方法,直接继承 BaseMapper 所有能力
}若 Mapper 接口较多,可在启动类添加 @MapperScan 统一扫描,无需每个接口加 @Mapper:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper") // 指定 Mapper 接口包路径
public class MybatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusDemoApplication.class, args);
}
}在 Service/Controller 中注入 Mapper,直接调用方法:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class UserMapperTest {
// 注入自定义 Mapper
@Autowired
private UserMapper userMapper;
@Test
public void testSelectAll() {
// 调用 BaseMapper 内置方法:查询所有数据
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}BaseMapper<T> 提供了单表 17 个核心方法,覆盖增删改查全场景,按功能分类如下:
示例:
User user = new User();
user.setUsername("张三");
user.setAge(20);
user.setEmail("zhangsan@xxx.com");
// 返回受影响行数
int rows = userMapper.insert(user);
// 插入后主键会自动回写到实体对象
System.out.println("插入成功,主键:" + user.getId());示例(条件删除):
// 条件构造器:删除 age < 18 的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lt("age", 18);
int rows = userMapper.delete(wrapper);示例:
// 根据主键更新
User user = new User();
user.setId(1L);
user.setUsername("张三更新");
userMapper.updateById(user);
// 条件更新:age=20 的用户,邮箱改为 xxx@xxx.com
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("age", 20);
User updateUser = new User();
updateUser.setEmail("xxx@xxx.com");
userMapper.update(updateUser, wrapper);查询是最常用功能,支持单条、列表、分页、计数等:
示例(分页查询):
// 配置分页插件(必须先配置,否则分页无效)
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
// 测试分页:第 1 页,每页 10 条
IPage<User> page = new Page<>(1, 10);
// 条件:age > 18
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 18);
IPage<User> userPage = userMapper.selectPage(page, wrapper);
// 分页结果
System.out.println("总条数:" + userPage.getTotal());
System.out.println("当前页数据:" + userPage.getRecords());MP 支持兼容原生 MyBatis,可在 Mapper Interface 中自定义方法,满足复杂业务需求:
适合简单 SQL,直接在方法上添加 @Select/@Insert 等注解:
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义注解查询:根据用户名模糊查询
@Select("SELECT * FROM t_user WHERE username LIKE CONCAT('%',#{username},'%')")
List<User> selectByUsernameLike(@Param("username") String username);
}适合多表关联、复杂查询,步骤:
在 resources 下创建 Mapper XML 文件(如 UserMapper.xml)
编写 SQL 映射
配置文件指定 XML 路径
XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 对应 Mapper 接口全类名 -->
<mapper namespace="com.example.mapper.UserMapper">
<!-- 自定义查询:根据年龄范围查询 -->
<select id="selectByAgeRange" resultType="com.example.entity.User">
SELECT * FROM t_user WHERE age BETWEEN #{minAge} AND #{maxAge}
</select>
</mapper>application.yml
mybatis-plus:
mapper-locations: classpath:mapper/*.xml # 指定 XML 路径
type-aliases-package: com.example.entity # 实体类别名Mapper 接口定义:
List<User> selectByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);MP 核心特性,无需手写 SQL 拼接条件,支持 =、>、<、LIKE、IN 等所有条件:
QueryWrapper:查询 / 删除条件构造
UpdateWrapper:更新条件构造
常用条件方法:
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", "张三") // 等于 =
.gt("age", 18) // 大于 >
.like("email", "@xxx.com") // 模糊查询 LIKE
.in("id", 1,2,3) // IN 查询
.orderByDesc("id"); // 排序若多个表需要相同的通用方法,可创建父类 Mapper 继承 BaseMapper,其他 Mapper 继承父类:
// 父类通用 Mapper
public interface BaseDao<T> extends BaseMapper<T> {
// 自定义通用方法
}
// 子类 Mapper 继承父类,获得所有能力
public interface UserMapper extends BaseDao<User> {}MP 支持逻辑删除(不物理删除数据,通过字段标记),配置后 delete 方法自动变为更新:
实体类添加逻辑删除字段:
@TableLogic // 标记逻辑删除字段
private Integer deleted; // 0=未删除,1=已删除配置文件开启:
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段名
logic-delete-value: 1 # 已删除值
logic-not-delete-value: 0 # 未删除值Mapper 职责单一:仅负责数据访问,业务逻辑放在 Service 层
优先使用条件构造器:避免手写 SQL,减少语法错误
非空字段更新:更新时仅传递需要修改的字段,MP 自动忽略 null
分页必须配置插件:否则 selectPage 只会查询所有数据
避免过度依赖:多表关联、复杂统计 SQL 建议用自定义 XML/ 注解
统一扫描 Mapper:使用 @MapperScan 替代单个 @Mapper 注解
Mapper 注入失败:检查 @Mapper/@MapperScan 注解是否添加,包路径是否正确
分页不生效:未配置 PaginationInnerInterceptor 分页插件
字段映射失败:实体类属性与数据库字段不一致,需加 @TableField("字段名")
逻辑删除无效:未配置 @TableLogic 注解或全局配置
Mapper Interface 是 MP 数据访问核心,继承 BaseMapper<T> 即可获得单表全量 CRUD 能力
无需 XML 即可完成基础操作,支持自定义方法兼容原生 MyBatis
核心能力:内置方法、条件构造器、分页、逻辑删除、通用复用
最佳实践:Mapper 专注数据访问,复杂 SQL 自定义扩展