官方文档:MyBatis-Plus
一、核心特性
- 无侵入性:仅增强MyBatis功能,不改变原有结构。
- 自动化CRUD:内置通用
BaseMapper
接口,单表操作无需手写SQL。 - 动态条件构造:通过
QueryWrapper
和LambdaQueryWrapper
链式调用生成复杂查询条件。 - 内置插件:分页插件、逻辑删除、性能分析等开箱即用。
- 代码生成器:一键生成实体类、Mapper、Service、Controller代码。
二、快速入门
1. 添加依赖(Spring Boot)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2. 配置数据源
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
3. 实体类与Mapper接口
核心注解:
- @TableName:指定实体类对应的表名。
@TableId:标识主键字段,支持多种生成策略:
IdType.AUTO
:数据库自增IdType.ASSIGN_ID
:雪花算法生成ID(默认)。
@TableField:处理字段映射,适用于:
- 字段名与数据库列名不一致
- 非数据库字段(
exist = false
) - 关键字冲突(使用转义符)。
实体类:使用注解映射表结构
@Data @TableName("user") // 表名注解 public class User { @TableId(type = IdType.AUTO) // 主键自增 private Long id; private String name; @TableField("user_age") // 字段名映射 private Integer age; }
Mapper接口:继承
BaseMapper
获得基础CRUD方法public interface UserMapper extends BaseMapper<User> {}
三、CRUD方法
方法名 | 作用 | 返回值 |
---|---|---|
insert(entity) | 插入记录 | 影响行数 |
deleteById(id) | 按ID删除 | 影响行数 |
updateById(entity) | 按ID更新 | 影响行数 |
selectById(id) | 按ID查询 | 实体对象 |
selectList(wrapper) | 条件查询列表 | 实体列表 |
selectPage(page, wrapper) | 分页查询 | IPage 分页对象 |
selectMaps(wrapper) | 返回Map结构结果 | Map列表 |
1. 插入操作
// 插入一条记录(返回影响行数)
int insert(User entity);
// 示例:插入用户
User user = new User();
user.setName("张三");
user.setAge(25);
int rows = userMapper.insert(user);
Long generatedId = user.getId(); // 获取自增ID(需配置主键策略)
2. 删除操作
// 按ID删除(返回影响行数)
int deleteById(Serializable id);
// 按条件删除(返回影响行数)
int delete(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
// 批量删除(返回影响行数)
int deleteBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
// 示例1:按ID删除
userMapper.deleteById(1L);
// 示例2:删除年龄大于30的用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(User::getAge, 30);
userMapper.delete(wrapper);
3. 更新操作
// 按ID更新(返回影响行数)
int updateById(@Param(Constants.ENTITY) User entity);
// 按条件更新(返回影响行数)
int update(@Param(Constants.ENTITY) User entity,
@Param(Constants.WRAPPER) Wrapper<User> updateWrapper);
// 示例1:更新用户信息
User user = new User();
user.setId(1L);
user.setName("李四");
userMapper.updateById(user);
// 示例2:条件更新(年龄+1)
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.setSql("age = age + 1"); // 直接写SQL表达式
userMapper.update(null, wrapper);
4. 查询操作
// 按ID查询
User selectById(Serializable id);
// 批量ID查询
List<User> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
// 按条件查询单条记录
User selectOne(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// 条件查询总数
Long selectCount(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// 条件查询列表
List<User> selectList(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// 示例:查询名字包含"张"的用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getName, "张");
List<User> users = userMapper.selectList(wrapper);
5. 高级查询方法
- 返回 Map 结构
// 查询结果为 Map 列表
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// 示例:获取用户ID和姓名映射
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName);
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
// 结果示例:[{id=1, name="张三"}, {id=2, name="李四"}]
- 返回特定字段
// 查询指定字段(返回 Object 列表)
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// 示例:查询所有用户ID
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId);
List<Object> ids = userMapper.selectObjs(wrapper); // [1, 2, 3...]
6. 自定义 SQL 方法
在 Mapper 接口中定义自定义方法:
public interface UserMapper extends BaseMapper<User> {
// 注解方式(简单SQL)
@Select("SELECT * FROM user WHERE age > #{age}")
List<User> selectByAge(@Param("age") Integer age);
// XML方式(复杂SQL)
List<User> selectComplexQuery(@Param("params") Map<String, Object> params);
}
XML 映射文件 (UserMapper.xml
):
<select id="selectComplexQuery" resultType="User">
SELECT * FROM user
WHERE name LIKE CONCAT(#{params.namePrefix}, '%')
AND status = #{params.status}
</select>
四、条件构造器
1. QueryWrapper:基础条件构造器
特点:基于字符串字段名,直接操作数据库列名
适用场景:快速构建简单查询条件
// 查询年龄>20且名字包含"张"的用户,按年龄降序排列
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("id", "name", "age") // 指定查询字段
.gt("age", 20)
.like("name", "张")
.orderByDesc("age");
List<User> users = userMapper.selectList(wrapper);
关键方法:
eq("column", value)
:等于ne("column", value)
:不等于gt("column", value)
:大于ge("column", value)
:大于等于lt("column", value)
:小于le("column", value)
:小于等于between("column", v1, v2)
:区间like("column", value)
:模糊匹配in("column", Collection)
:IN 查询
注意事项:
- 字段名硬编码易出错,推荐仅在简单场景使用
- 字段名与数据库列名严格一致(除非配置了全局策略)
2. LambdaQueryWrapper:类型安全条件构造器
特点:通过 Lambda 表达式引用实体字段,编译期类型检查
优势:避免字段名拼写错误,支持 IDE 智能提示
// 查询邮箱不为空且状态为启用的用户
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.select(User::getId, User::getUsername)
.isNotNull(User::getEmail)
.eq(User::getStatus, 1)
.orderByAsc(User::getCreateTime);
List<User> users = userMapper.selectList(lambdaWrapper);
方法对照:
eq(User::getField, value)
→eq("field", value)
like(User::getField, value)
→like("field", value)
嵌套条件示例:
wrapper.and(w -> w.lt(User::getAge, 40).or().isNull(User::getEmail))
.or().between(User::getScore, 60, 90);
生成 SQL:
WHERE (age < 40 OR email IS NULL) OR score BETWEEN 60 AND 90
3. UpdateWrapper:更新条件构造器
核心作用:构建更新操作的条件和字段设置
示例1:直接设置值
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("balance", 1000) // 设置字段值
.set("vip_level", 2)
.eq("id", 1L);
userMapper.update(null, updateWrapper);
示例2:使用 Lambda 表达式 + SQL 片段
LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.setSql("balance = balance - 200") // 直接写SQL表达式
.in(User::getId, Arrays.asList(1L, 3L, 5L))
.eq(User::getStatus, 1);
userMapper.update(null, lambdaUpdate);
特殊方法:
set("column", value)
:设置更新字段setSql("sql片段")
:直接拼接 SQL 语句(慎用,需防 SQL 注入)
4. 复杂条件组合
逻辑运算符灵活组合,支持多层级嵌套条件
场景:查询(年龄<18 或 年龄>60)且姓"王"的用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.likeRight(User::getName, "王")
.and(wq -> wq.lt(User::getAge, 18).or().gt(User::getAge, 60));
// 生成SQL:
// WHERE (name LIKE '王%') AND (age < 18 OR age > 60)
条件优先级控制:通过括号明确逻辑关系
wrapper.nested(wq -> wq.eq(...).or().eq(...)) // 嵌套条件生成括号
.or().eq(...)
5. 最佳实践与调试技巧
调试技巧:
开启 SQL 日志打印:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
打印完整条件:
System.out.println(wrapper.getCustomSqlSegment());
性能优化:
- 避免在循环中创建 Wrapper(复用对象)
- 复杂查询优先使用 XML 编写 SQL
- 批量操作使用
Service
层的saveBatch
方法
Null 值处理策略:
- 默认忽略
null
条件(需手动处理 IS NULL) 强制包含 null 条件:
wrapper.eq(Objects.nonNull(param), User::getField, param)
方法速查表:
方法名 | 作用 |
---|---|
.exists("子查询") | 添加 EXISTS 条件 |
.notExists("子查询") | 添加 NOT EXISTS 条件 |
.apply("SQL片段") | 拼接自定义 SQL(需防注入) |
.last("LIMIT 1") | 追加 SQL 末尾(分页慎用) |
.having("SUM(age)>30") | HAVING 条件 |
选择策略:
- 简单条件 →
LambdaQueryWrapper
(首选) - 复杂更新 →
LambdaUpdateWrapper
+setSql
- 需要动态字段 →
QueryWrapper
- 极高灵活性 → 自定义 XML SQL + Wrapper 条件混合使用
五、高级功能
1. 分页插件
配置分页拦截器:
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }
使用分页查询:
Page<User> page = new Page<>(1, 10); // 当前页,每页条数 userMapper.selectPage(page, queryWrapper); List<User> records = page.getRecords();
2. 逻辑删除
配置全局逻辑删除:
mybatis-plus: global-config: db-config: logic-delete-field: deleted # 删除标记字段 logic-delete-value: 1 # 删除后的值 logic-not-delete-value: 0 # 未删除的值
- 操作示例:调用
deleteById
实际执行UPDATE user SET deleted=1 WHERE id=xx
。
3. 代码生成器
引入依赖:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency>
- 配置生成策略:指定表名、包路径、模板引擎(如Freemarker),自动生成Entity、Mapper、Service等代码。
六、Service层封装
MyBatis-Plus提供通用Service接口IService
,进一步简化业务层代码:
public interface UserService extends IService<User> {}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
批量操作示例:
List<User> userList = new ArrayList<>(); // 添加数据... userService.saveBatch(userList); // 批量插入,性能优于逐条插入。
七、最佳实践
- 优先使用Lambda表达式:避免字段名硬编码,提升代码可维护性。
- 分页与性能优化:结合
rewriteBatchedStatements=true
参数优化批量插入性能。 - 逻辑删除慎用:频繁查询可能导致性能下降,建议归档历史数据替代。
SQL监控:启用性能分析插件,识别慢查询:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
八、常见问题
字段映射失败:检查
@TableField
注解或开启驼峰转换:mybatis-plus: configuration: map-underscore-to-camel-case: true
- Mapper扫描失败:在启动类添加
@MapperScan("com.example.mapper")
。 - 主键冲突:确认
@TableId
的type
策略与数据库一致(如自增需设置AUTO
)。
评论 (0)