1. MyBatis-Plus核心CRUD操作解析
作为Java开发者,当我们需要快速构建数据访问层时,MyBatis-Plus提供的CRUD功能绝对是生产力利器。相比原生MyBatis需要手动编写每个SQL语句,MyBatis-Plus通过继承BaseMapper接口就能获得18种常用数据操作方法。我在多个企业级项目中实践发现,合理使用这些方法可以节省约70%的DAO层代码量。
最新3.5.17版本中,MyBatis-Plus对Lambda表达式查询进行了重点优化,使得代码不仅简洁而且具备编译期类型安全检查。下面通过用户表(user)的增删改查示例,演示如何高效运用这些API。
1.1 环境准备与基础配置
首先确保你的Spring Boot项目引入正确版本的依赖。对于MyBatis-Plus 3.5.17,推荐使用Spring Boot 2.7.x版本:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.17</version>
</dependency>
实体类需要添加@TableName注解指定表名,字段用@TableField映射(驼峰转下划线默认开启):
java复制@Data
@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private Integer age;
@TableField("email_address")
private String email;
}
注意:当字段名与数据库列名不一致时,必须显式使用@TableField注解,否则会报绑定异常。
1.2 Mapper接口的魔法
只需继承BaseMapper并指定泛型类型,你就免费获得了全套CRUD方法:
java复制public interface UserMapper extends BaseMapper<User> {
// 无需任何方法声明
}
这个简单的接口背后,MyBatis-Plus通过动态代理机制注入了18个基础方法。通过IDEA的代码提示可以看到包含insert、deleteById、update、selectList等完整操作集合。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 增删改查深度实践
2.1 插入操作的三种姿势
基础插入:自动回填主键到实体对象
java复制User user = new User();
user.setUsername("mpUser");
user.setAge(25);
int rows = userMapper.insert(user);
System.out.println("插入ID:" + user.getId());
批量插入:使用executeBatch提升性能
java复制List<User> users = Arrays.asList(
new User("user1", 20),
new User("user2", 22)
);
userMapper.insertBatchSomeColumn(users); // 需要开启SQL注入器
存在判断插入:避免重复数据
java复制LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, "mpUser");
if(userMapper.selectCount(wrapper) == 0){
userMapper.insert(user);
}
踩坑记录:批量插入时MySQL的max_allowed_packet参数可能导致大事务失败,建议每500条提交一次。
2.2 删除操作的业务实践
逻辑删除配置(application.yml):
yaml复制mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段名
logic-not-delete-value: 0 # 未删除值
logic-delete-value: 1 # 删除值
物理删除示例:
java复制// 按ID删除
userMapper.deleteById(1L);
// 按条件删除
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getAge, 25)
.like(User::getUsername, "test");
userMapper.delete(wrapper);
逻辑删除特点:
- 自动将delete语句转为update
- 查询自动附加deleted=0条件
- 需要实体类添加@TableLogic注解
2.3 更新操作的高级用法
全量更新(null值会覆盖数据库):
java复制User user = userMapper.selectById(1L);
user.setAge(26);
userMapper.updateById(user);
动态更新(只修改非null字段):
java复制User user = new User();
user.setId(1L);
user.setEmail("new@mail.com");
userMapper.updateById(user); // 只更新email字段
条件更新:
java复制LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(User::getAge, 30)
.eq(User::getUsername, "admin");
userMapper.update(null, wrapper);
性能提示:批量更新时,使用wrapper.in()替代循环单条更新效率提升5倍以上。
2.4 查询的多种姿势
基础查询:
java复制// 按ID查询
User user = userMapper.selectById(1L);
// 批量ID查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L));
// 条件查询
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getUsername)
.between(User::getAge, 20, 30)
.orderByDesc(User::getCreateTime);
List<User> userList = userMapper.selectList(wrapper);
分页查询:
java复制// 配置分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
// 使用分页
Page<User> page = new Page<>(1, 10);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(User::getAge, 18);
Page<User> result = userMapper.selectPage(page, wrapper);
自定义SQL分页:
java复制@Select("SELECT * FROM user ${ew.customSqlSegment}")
Page<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);
3. 实战避坑指南
3.1 常见异常处理
问题1:Property 'id' not found on 'java.lang.Long'
- 原因:实体类未添加@TableId注解
- 解决:确保主键字段有正确注解
问题2:nested exception is org.apache.ibatis.binding.BindingException
- 原因:Mapper方法名与BaseMapper提供的方法冲突
- 解决:重命名自定义方法或使用@Mapper注解指定方法名
问题3:分页查询结果total为0
- 检查是否配置分页插件
- 确认没有在wrapper中手动添加limit条件
3.2 性能优化建议
- 大批量插入使用insertBatchSomeColumn(需配置SQL注入器)
- 查询指定字段避免select *
- 频繁查询字段考虑添加@TableField(fill = FieldFill.INSERT_UPDATE)
- 复杂查询优先使用LambdaWrapper保证类型安全
3.3 与若依框架整合
对于使用若依4.8.3非分离版的用户,改造步骤:
- 替换mybatis-spring-boot-starter为mybatis-plus-boot-starter
- 修改所有Mapper继承BaseMapper
- 将XML中的
标签改为 语法 - 添加分页插件配置
4. 扩展应用场景
4.1 多租户实现方案
通过TenantLineInnerInterceptor实现:
java复制interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(
new TenantLineHandler() {
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public Expression getTenantId() {
return new StringValue("当前租户ID");
}
}
));
4.2 数据权限控制
结合@DataScope注解实现:
java复制@DataScope(deptAlias = "d", userAlias = "u")
public List<User> selectUserList(User user) {
return userMapper.selectUserList(user);
}
4.3 乐观锁实践
- 添加@Version字段
- 配置乐观锁插件
- 更新时自动带版本条件
在实际项目开发中,我发现合理组合MyBatis-Plus的CRUD功能可以应对90%以上的数据操作场景。对于特别复杂的查询,仍然推荐使用XML方式实现,保持灵活性。最新版本对Lambda表达式的支持让代码更加优雅,建议新项目直接采用LambdaWrapper写法。
