1. MyBatis Plus 核心价值与定位
作为 MyBatis 的增强工具,MyBatis Plus 在保留原生 MyBatis 所有特性的基础上,针对单表 CRUD 操作进行了深度封装。我在实际项目中最直观的感受是:它让 DAO 层代码量减少了 70% 以上,同时通过智能化的 SQL 自动生成,避免了 90% 的手写 SQL 错误。不同于其他 ORM 框架的"全自动"理念,MyBatis Plus 采用了"半自动化"设计哲学——既提供便捷的 CRUD 封装,又保留 MyBatis 原生 SQL 的灵活性。
2. 基础环境搭建实战
2.1 依赖配置要点
以 Spring Boot 项目为例,最新稳定版依赖配置如下:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
这里有个容易踩的坑:如果项目中同时存在 MyBatis 原生依赖,必须确保版本号一致。我曾遇到过因为 mybatis-spring 版本冲突导致的"Invalid bound statement"异常,解决方案是显式声明统一版本:
xml复制<properties>
<mybatis.version>3.5.13</mybatis.version>
</properties>
2.2 配置类关键项
java复制@Configuration
@MapperScan("com.xxx.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> {
// 关闭MP自带的逻辑删除字段自动填充
configuration.setLogicDeleteField("del_flag");
};
}
}
3. 核心功能深度解析
3.1 实体类注解体系
java复制@Data
@TableName(value = "sys_user", autoResultMap = true)
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(value = "username", condition = SqlCondition.LIKE)
private String name;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Version
private Integer version;
@TableLogic
private Integer deleted;
}
@TableName的autoResultMap属性在涉及类型处理器(如 JSON 字段)时特别有用@TableField的condition属性可以自定义查询条件匹配方式- 字段填充策略需要配合自定义的
MetaObjectHandler实现
3.2 条件构造器实战技巧
java复制// 复杂查询示例
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName)
.nested(i -> i.like(User::getName, "张").or().like(User::getName, "李"))
.between(User::getCreateTime, startDate, endDate)
.orderByDesc(User::getCreateTime);
经验之谈:
- 避免在循环中构建条件构造器,会导致 SQL 解析性能下降
apply()方法可以嵌入原生 SQL 片段,但要严防 SQL 注入- 使用
last()追加 SQL 语句时,注意不要破坏 WHERE 子句结构
4. 高级特性应用指南
4.1 多租户实现方案
java复制public class TenantInterceptor implements InnerInterceptor {
@Override
public void beforeQuery(Executor executor, MappedStatement ms,
Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) {
// 获取当前租户ID
String tenantId = TenantContext.getCurrentTenant();
// 修改SQL
String newSql = boundSql.getSql() + " AND tenant_id = '" + tenantId + "'";
resetSql(ms, boundSql, newSql);
}
private void resetSql(MappedStatement ms, BoundSql boundSql, String sql) {
// 使用反射修改BoundSql的sql属性
Field field = BoundSql.class.getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, sql);
}
}
4.2 逻辑删除最佳实践
配置逻辑删除后,所有删除操作自动变为更新操作。需要注意:
- 查询时会自动附加
deleted = 0条件 - 需要手动处理关联表数据(建议使用数据库外键约束)
- 唯一索引字段需要包含删除标记字段
yaml复制mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段
logic-not-delete-value: 0 # 未删除值
logic-delete-value: 1 # 删除值
5. 性能优化与监控
5.1 SQL 执行分析插件
java复制@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(1000); // SQL执行最大时长(ms)
interceptor.setFormat(true); // 是否格式化SQL
return interceptor;
}
5.2 二级缓存整合
与 Redis 集成示例:
java复制@Bean
public MybatisRedisCacheFactory mybatisRedisCacheFactory(RedisTemplate<String, Object> redisTemplate) {
return new MybatisRedisCacheFactory(redisTemplate) {
@Override
public Cache createCache(String id) {
return new MybatisRedisCache(id, redisTemplate) {
@Override
public String getId() {
return "mybatis:" + super.getId();
}
};
}
};
}
6. 常见问题排查手册
6.1 字段映射异常
现象:查询返回的实体类部分字段为 null
排查步骤:
- 检查数据库字段命名风格配置:
yaml复制mybatis-plus: configuration: map-underscore-to-camel-case: true - 确认
@TableField注解的 value 值是否正确 - 使用
@TableField(exist=false)标注非表字段
6.2 分页失效问题
可能原因:
- 未注册分页插件
- 分页参数未放在方法第一个参数位置
- 自定义 SQL 未使用
${ew.customSqlSegment}
7. 扩展开发指南
7.1 自定义 SQL 注入器
实现批量插入功能示例:
java复制public class BatchInsertInjector extends AbstractSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
return Collections.singletonList(new BatchInsert());
}
}
public class BatchInsert extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(...) {
String sql = "<script>INSERT INTO %s %s VALUES %s</script>";
// 构建SQL逻辑
return addInsertMappedStatement(mapperClass, modelClass, "batchInsert", sqlSource);
}
}
7.2 类型处理器开发
处理 JSON 字段示例:
java复制@MappedTypes(JSONObject.class)
public class JsonTypeHandler extends BaseTypeHandler<JSONObject> {
@Override
public void setNonNullParameter(...) {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public JSONObject getNullableResult(ResultSet rs, String columnName) {
return JSON.parseObject(rs.getString(columnName));
}
}
8. 工程化实践建议
8.1 项目目录规范
推荐结构:
code复制src/main/java
├── config
│ └── MybatisPlusConfig.java
├── entity
│ ├── base
│ │ └── BaseEntity.java
│ └── business
│ └── User.java
├── mapper
│ ├── base
│ │ └── BaseMapper.java
│ └── business
│ └── UserMapper.java
└── service
├── impl
│ └── UserServiceImpl.java
└── UserService.java
8.2 多数据源方案
java复制@Configuration
@MapperScan(basePackages = "com.xxx.mapper.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class Db1DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.db1")
public DataSource db1DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/db1/*.xml"));
return factory.getObject();
}
@Bean
public SqlSessionTemplate db1SqlSessionTemplate(
@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
9. 版本升级注意事项
从 3.x 升级到最新版需要关注:
- 移除已废弃的
execute()方法调用 - 调整
@TableField的fill属性配置方式 - 分页插件改为通过
MybatisPlusInterceptor配置 - 新版乐观锁字段需要添加
@Version注解
建议升级步骤:
- 先在测试环境验证
- 使用 MyBatis Plus 提供的迁移工具检查兼容性
- 重点关注动态表名、SQL 注入器等自定义功能
10. 最佳实践总结
经过多个项目的实战验证,以下配置组合表现最优:
yaml复制mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.xxx.entity
configuration:
cache-enabled: true
lazy-loading-enabled: true
multiple-result-sets-enabled: true
use-column-label: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
banner: false
关键建议:
- 复杂查询仍推荐使用 XML 方式
- 批量操作优先选择
service.saveBatch()方法 - 多表关联查询不要强行使用 MP 的条件构造器
- 生产环境关闭 SQL 日志打印
