MyBatis-Plus
一、MyBatis-Plus 概述
1. 定义与定位
MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做改变,致力于简化开发、提升效率,是国内最流行的 MyBatis 扩展框架之一。
2. 核心优势
- 无侵入:不改变现有代码结构,引入即可使用。
- 损耗小:启动即自动注入基础 CRUD,性能接近原生 MyBatis。
- 强大 CRUD:内置通用 Mapper,少量配置即可实现单表 80% 以上的 CRUD 操作。
- Lambda 调用:支持 Lambda 表达式,避免字段名拼写错误。
- 丰富插件:内置分页、乐观锁、逻辑删除、多租户等实用插件。
- 代码生成:一键生成 Entity、Mapper、Service、Controller 等代码。
二、核心基础功能
1. 通用 Mapper(BaseMapper)
Mapper 接口继承 BaseMapper<T>,即可自动拥有单表的 CRUD 能力,无需编写 XML 或 SQL。
核心方法:
- 插入:
insert(T entity)、insertBatchSomeColumn(List<T> entityList) - 删除:
deleteById(Serializable id)、delete(Wrapper<T> wrapper) - 更新:
updateById(T entity)、update(T entity, Wrapper<T> updateWrapper) - 查询:
selectById(Serializable id)、selectList(Wrapper<T> queryWrapper)、selectPage(Page<T> page, Wrapper<T> queryWrapper)
2. 条件构造器(Wrapper)
用于构建 SQL 查询条件,替代手写 SQL 的 WHERE 子句,类型安全且灵活。
核心实现类:
QueryWrapper:查询条件构造器,用于 SELECT、DELETE、UPDATE。UpdateWrapper:更新条件构造器,可设置 SET 字段。LambdaQueryWrapper:Lambda 形式的查询构造器,通过方法引用(如User::getName)避免字段名错误。LambdaUpdateWrapper:Lambda 形式的更新构造器。
常用方法:
- 等值:
eq(等于)、ne(不等于) - 范围:
gt(大于)、lt(小于)、between(在...之间) - 模糊:
like(包含)、likeLeft(左模糊)、likeRight(右模糊) - 排序:
orderByAsc(升序)、orderByDesc(降序) - 逻辑:
and、or、nested(嵌套条件)
3. 分页插件
基于 MyBatis 物理分页,支持多种数据库(MySQL、Oracle 等)。
使用步骤:
- 注册插件:在配置类中注册
PaginationInnerInterceptor,指定数据库类型。 - 调用方法:创建
Page<T>对象(传入当前页、每页大小),调用selectPage方法。
示例:
Page<User> page = new Page<>(1, 10);
Page<User> result = userMapper.selectPage(page, new LambdaQueryWrapper<User>().eq(User::getAge, 18));
4. 代码生成器
根据数据库表结构,一键生成 Entity、Mapper、Service、Controller 等代码,支持自定义模板。
核心组件:
FastAutoGenerator(新版推荐):通过链式调用配置数据源、包路径、策略等。
三、扩展增强功能
1. 逻辑删除
并非真正删除数据,而是通过字段(如 deleted)标记为“已删除”,查询时自动过滤。
实现步骤:
- 数据库表添加
deleted字段(TINYINT 类型,0 未删除,1 已删除)。 - 实体类字段添加
@TableLogic注解。 - 全局配置(可选):
mybatis-plus: global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0
2. 乐观锁
通过版本号(version)控制并发,更新时检查版本号是否一致,一致则更新并递增版本号。
实现步骤:
- 数据库表添加
version字段(INT 类型,默认值 1)。 - 实体类字段添加
@Version注解。 - 注册
OptimisticLockerInnerInterceptor插件。
3. ActiveRecord 模式
实体类继承 Model<T>,即可直接调用实体类方法进行 CRUD,无需注入 Mapper。
示例:
User user = new User();
user.setName("张三");
user.insert(); // 直接插入
User result = new User().selectById(1); // 直接查询
四、高级特性
1. 多租户支持
通过租户 ID(如 tenant_id)实现不同租户的数据隔离。
实现步骤:
- 实现
TenantLineHandler接口,重写getTenantId()(获取当前租户 ID)、ignoreTable()(指定忽略的表)。 - 注册
TenantLineInnerInterceptor插件。
2. 动态表名
运行时动态修改表名,适用于分表场景(如 user_2024、user_2025)。
实现步骤:
- 实现
TableNameHandler接口,重写dynamicTableName()(根据原表名返回动态表名)。 - 注册
DynamicTableNameInnerInterceptor插件。
3. 主键生成策略
通过 @TableId 注解的 type 属性指定主键生成方式:
IdType.ASSIGN_ID(默认):雪花算法生成 Long 类型主键(分布式场景)。IdType.AUTO:数据库自增主键。IdType.INPUT:用户手动输入主键。IdType.ASSIGN_UUID:生成 UUID 作为主键。
五、Spring Boot 集成与配置
1. 依赖引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
2. 基础配置(application.yml)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus_demo?serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.example.demo.entity
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL 日志
3. 插件注册
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁
return interceptor;
}
}
六、最佳实践与常见问题
1. 最佳实践
- 分层架构:Controller → Service → Mapper,Service 处理业务逻辑,Mapper 仅负责数据库操作。
- Lambda Wrapper 优先:使用
LambdaQueryWrapper避免字段名错误。 - 代码生成器定制:根据项目规范定制模板,添加 Swagger 注解、统一返回结果等。
- SQL 日志开启:开发环境开启 SQL 日志,便于调试。
2. 常见问题
- 分页不生效:检查是否注册
PaginationInnerInterceptor,且数据库类型(DbType)正确。 - 逻辑删除未生效:检查实体类是否添加
@TableLogic注解,全局配置是否正确。 - 乐观锁未生效:检查是否注册
OptimisticLockerInnerInterceptor,更新时是否传入version字段。