外观
MyBatis-Plus 笔记
约 1896 字大约 6 分钟
2025-08-16
一、MyBatis-Plus 简介
1.1 什么是 MyBatis-Plus?
MyBatis-Plus 是在 MyBatis 基础上只做增强不做改变的持久层框架,为简化开发、提高效率而生。它具有 MyBatis 的所有特性,同时提供了更多开箱即用的功能。
1.2 MyBatis-Plus 核心特点
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,实现单表大部分 CRUD 操作
- 支持 Lambda 形式调用:通过 Lambda 表达式编写查询条件,避免字段名写错
- 支持主键自动生成:支持多种主键策略(包括分布式唯一 ID 生成器)
- 内置代码生成器:快速生成实体类、Mapper、Service、Controller 层代码
- 内置分页插件:基于 MyBatis 物理分页,简化分页操作
1.3 MyBatis 与 MyBatis-Plus 区别
| 特性 | MyBatis | MyBatis-Plus |
|---|---|---|
| SQL 语句 | 需要手动编写 | 基本 CRUD 无需编写 SQL |
| 条件构造 | 需手动拼接 | 提供强大的条件构造器 |
| Lambda 支持 | 不支持 | 支持 Lambda 表达式 |
| 主键生成 | 需手动处理 | 内置多种主键策略 |
| 分页 | 需手动实现 | 内置分页插件 |
| 驼峰映射 | 默认关闭 | 默认开启 |
| 代码生成 | 无 | 内置代码生成器 |
二、环境搭建
2.1 依赖配置
Maven 配置:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>Gradle 配置:
implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3.1'2.2 基础配置
application.yml 配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 开启驼峰命名转换
global-config:
db-config:
id-type: auto # 主键生成策略2.3 启动类配置
@SpringBootApplication
@MapperScan("com.example.mapper") // 扫描 Mapper 接口
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}三、基础 CRUD 操作
3.1 实体类定义
@Data
@TableName("t_user") // 指定表名
public class User {
@TableId(type = IdType.AUTO) // 主键策略
private Long id;
@TableField("name") // 指定字段名
private String username;
private Integer age;
private String email;
}3.2 Mapper 接口
public interface UserMapper extends BaseMapper<User> {
// 继承 BaseMapper,自动获得 CRUD 方法
}3.3 基本 CRUD 使用
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 插入
public int insertUser() {
User user = new User();
user.setUsername("John");
user.setAge(25);
user.setEmail("john@example.com");
return userMapper.insert(user);
}
// 查询
public User selectById(Long id) {
return userMapper.selectById(id);
}
public List<User> selectAll() {
return userMapper.selectList(null);
}
// 更新
public int updateUser() {
User user = new User();
user.setId(1L);
user.setAge(26);
return userMapper.updateById(user);
}
// 删除
public int deleteUser(Long id) {
return userMapper.deleteById(id);
}
}四、条件构造器
4.1 QueryWrapper
用于查询条件构造:
// 查询 name='John' 且 age>20 的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John").gt("age", 20);
List<User> users = userMapper.selectList(queryWrapper);
// 查询 name 包含 'o',age 在 20 到 30 之间,且 email 不为空的用户,按 age 降序
queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "o")
.between("age", 20, 30)
.isNotNull("email")
.orderByDesc("age");
users = userMapper.selectList(queryWrapper);4.2 LambdaQueryWrapper
使用 Lambda 表达式,避免字段名写错:
// 查询 name='John' 且 age>20 的用户
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getUsername, "John")
.gt(User::getAge, 20);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
// 查询 name 包含 'o',age 在 20 到 30 之间,且 email 不为空的用户,按 age 降序
lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(User::getUsername, "o")
.between(User::getAge, 20, 30)
.isNotNull(User::getEmail)
.orderByDesc(User::getAge);
users = userMapper.selectList(lambdaQueryWrapper);4.3 UpdateWrapper
用于更新操作:
// 将 name='John' 的用户 age 更新为 26
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", "John")
.set("age", 26);
userMapper.update(null, updateWrapper);
// 使用 Lambda
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getUsername, "John")
.set(User::getAge, 26);
userMapper.update(null, lambdaUpdateWrapper);4.4 常用查询条件
| 方法 | 说明 | 示例 |
|---|---|---|
eq | 等于 | eq("name", "John") |
ne | 不等于 | ne("age", 20) |
gt | 大于 | gt("age", 20) |
ge | 大于等于 | ge("age", 20) |
lt | 小于 | lt("age", 30) |
le | 小于等于 | le("age", 30) |
like | 模糊查询 | like("name", "o") |
between | 区间查询 | between("age", 20, 30) |
in | IN 查询 | in("age", Arrays.asList(20, 25, 30)) |
isNull | 为空 | isNull("email") |
isNotNull | 不为空 | isNotNull("email") |
orderByAsc | 升序排序 | orderByAsc("age") |
orderByDesc | 降序排序 | orderByDesc("age") |
五、分页查询
5.1 分页插件配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}5.2 分页查询使用
// 第1页,每页5条记录
Page<User> page = new Page<>(1, 5);
// 执行分页查询
IPage<User> userPage = userMapper.selectPage(page, null);
// 获取分页信息
System.out.println("当前页: " + userPage.getCurrent());
System.out.println("每页条数: " + userPage.getSize());
System.out.println("总条数: " + userPage.getTotal());
System.out.println("总页数: " + userPage.getPages());
System.out.println("数据: " + userPage.getRecords());
// 带条件的分页查询
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20);
userPage = userMapper.selectPage(page, queryWrapper);六、常用注解
6.1 实体类注解
| 注解 | 说明 | 示例 |
|---|---|---|
@TableName | 指定表名 | @TableName("t_user") |
@TableId | 指定主键 | @TableId(type = IdType.AUTO) |
@TableField | 指定字段 | @TableField("user_name") |
@TableLogic | 逻辑删除 | @TableLogic(value = "0", delval = "1") |
6.2 主键策略
public enum IdType {
AUTO(0), // 数据库ID自增
NONE(1), // 无状态
INPUT(2), // 用户输入ID
ASSIGN_ID(3), // 分配ID(使用雪花算法)
ASSIGN_UUID(4), // 分配UUID
// 其他策略...
}6.3 逻辑删除
配置:
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值实体类:
public class User {
@TableLogic
private Integer isDelete;
}使用:
// 删除操作会自动转换为更新操作
userMapper.deleteById(1L);
// 实际执行:UPDATE user SET is_delete=1 WHERE id=1 AND is_delete=0
// 查询操作会自动过滤已删除数据
userMapper.selectById(1L);
// 实际执行:SELECT * FROM user WHERE id=1 AND is_delete=0七、Service 层封装
7.1 Service 接口
public interface IUserService extends IService<User> {
// 可以在这里添加自定义方法
}7.2 Service 实现
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
// 可以在这里实现自定义方法
}7.3 Service 使用
@Service
public class UserService {
@Autowired
private IUserService userService;
public void example() {
// 保存
User user = new User();
user.setUsername("John");
userService.save(user);
// 批量保存
List<User> users = Arrays.asList(new User(), new User());
userService.saveBatch(users);
// 分页查询
Page<User> page = new Page<>(1, 5);
IPage<User> userPage = userService.page(page);
// 条件查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 20);
List<User> userList = userService.list(wrapper);
}
}八、代码生成器
8.1 依赖配置
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>8.2 代码生成器配置
public class CodeGenerator {
public static void main(String[] args) {
// 1. 创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2. 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("YourName");
gc.setOpen(false);
gc.setServiceName("%sService"); // 去掉Service接口的首字母I
mpg.setGlobalConfig(gc);
// 3. 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 4. 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("demo");
pc.setParent("com.example");
mpg.setPackageInfo(pc);
// 5. 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 使用 Lombok
strategy.setRestControllerStyle(true); // 使用 REST 风格
strategy.setInclude("t_user"); // 要生成的表名
mpg.setStrategy(strategy);
// 6. 执行生成
mpg.execute();
}
}九、最佳实践
9.1 实体类设计
@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(value = "user_name", condition = SqlCondition.LIKE)
private String username;
@TableField(exist = false)
private String fullName; // 非表字段
@TableLogic
private Integer isDelete;
@Version
private Integer version; // 乐观锁版本号
}9.2 乐观锁
配置:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}实体类:
public class User {
@Version
private Integer version;
}使用:
// 1. 查询数据
User user = userMapper.selectById(1L);
// 2. 更新数据
user.setAge(26);
userMapper.updateById(user);
// 生成的SQL:UPDATE user SET age=26, version=version+1 WHERE id=1 AND version=原来的version9.3 常见问题解决
问题1:字段名与数据库不一致
解决方案:
@TableField("user_name")
private String username;问题2:查询结果为空
解决方案:
- 检查表名、字段名是否正确
- 检查数据库连接是否正确
- 使用
@TableField(exist = false)标记非表字段
问题3:分页查询无效
解决方案:
- 确保已配置分页插件
- 确保使用
selectPage或page方法
