文档
MyBatis-Plus 实战入门教程
第一章:MyBatis vs MyBatis-Plus
MyBatis 的痛点:
// MyBatis 原始写法——每个单表查询都要写 SQL
@Select("SELECT * FROM user WHERE age BETWEEN #{min} AND #{max}")
List<User> findByAgeRange(@Param("min") int min, @Param("max") int max);
MyBatis-Plus 让这些消失:
// 一行 SQL 不用写
List<User> users = userMapper.selectList(
new LambdaQueryWrapper<User>().between(User::getAge, minAge, maxAge)
);
第二章:Entity 注解详解
| 注解 | 说明 |
|---|---|
@TableName("user") |
指定表名(默认类名驼峰转下划线) |
@TableId(type=IdType.AUTO) |
主键策略:AUTO/ASSIGN_ID(雪花)/INPUT |
@TableField("nick_name") |
指定字段映射(默认驼峰→下划线) |
@TableField(exist=false) |
标记非数据库字段 |
@TableField(fill=Fill.INSERT) |
插入时自动填充(配合 MetaObjectHandler) |
@TableLogic |
逻辑删除字段 |
@Version |
乐观锁版本号 |
第三章:条件构造器进阶
Wrapper 层级
Wrapper
├── AbstractWrapper(条件)
│ ├── QueryWrapper(普通查询)
│ │ └── LambdaQueryWrapper(Lambda 类型安全查询)
│ └── UpdateWrapper(更新条件)
│ └── LambdaUpdateWrapper
└── AbstractChainWrapper(链式调用)
常用操作
// 查询数量
long count = userMapper.selectCount(
new LambdaQueryWrapper<User>().gt(User::getAge, 18)
);
// 查询单个
User user = userMapper.selectOne(
new LambdaQueryWrapper<User>().eq(User::getEmail, "test@test.com")
);
// 只查指定字段
wrapper.select(User::getId, User::getName);
// 排除字段
wrapper.select(User.class, info ->
!info.getColumn().equals("password")
);
第四章:分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor interceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页
interceptor.addInnerInterceptor(
new PaginationInnerInterceptor(DbType.MYSQL)
);
// 防全表更新/删除
interceptor.addInnerInterceptor(
new BlockAttackInnerInterceptor()
);
return interceptor;
}
}
第五章:代码生成器
MP 的代码生成器可以一键生成 Entity、Mapper、Service、Controller:
FastAutoGenerator.create("jdbc:mysql://localhost:3306/test", "root", "root")
.globalConfig(builder -> builder.author("dev").outputDir("src/main/java"))
.packageConfig(builder -> builder.parent("com.example"))
.strategyConfig(builder -> builder.addInclude("user").entityBuilder().enableLombok())
.execute();
思考题
- MyBatis-Plus 的 BaseMapper 底层是怎么实现的?它怎么知道
selectById要去哪张表? - 逻辑删除和物理删除各适合什么场景?生产环境为什么更推荐逻辑删除?
- LambdaQueryWrapper 和普通 QueryWrapper 的区别是什么?前者怎么做到类型安全的?