MyBatis Plus 完整使用指南
MyBatis Plus 是一个强大的 MyBatis 增强工具,简化开发、提高效率。下面详细介绍其使用方法:
1. 快速开始
1.1 添加依赖
Maven:
<dependencies>
<!-- MyBatis Plus 核心依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 代码生成器(可选) -->
<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.32</version>
</dependency>
</dependencies>
Gradle:
dependencies {
implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3.1'
implementation 'com.baomidou:mybatis-plus-generator:3.5.3.1'
implementation 'org.freemarker:freemarker:2.3.32'
}
1.2 基础配置
application.yml:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reggie?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志
map-underscore-to-camel-case: true # 下划线转驼峰
global-config:
db-config:
id-type: auto # 主键策略:AUTO-数据库自增,INPUT-手动输入,ASSIGN_ID-雪花算法
logic-delete-field: deleted # 逻辑删除字段
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
2. 实体类映射
2.1 基础实体类
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("user") // 指定表名,默认类名小写
public class User {
@TableId(type = IdType.AUTO) // 主键策略
private Long id;
private String username;
private String password;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时自动填充
private LocalDateTime updateTime;
@TableLogic // 逻辑删除注解
private Integer deleted;
// 排除非表字段
@TableField(exist = false)
private String confirmPassword;
}
2.2 枚举类型处理
// 枚举定义
public enum GenderEnum {
MALE(1, "男"),
FEMALE(2, "女");
private final Integer code;
private final String desc;
GenderEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
// getter...
}
// 实体类中使用枚举
@Data
@TableName("user")
public class User {
// 自动映射枚举的 code 值到数据库
private GenderEnum gender;
}
3. Mapper 接口
3.1 基础 Mapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
// 继承 BaseMapper 即拥有基础的 CRUD 方法
public interface UserMapper extends BaseMapper<User> {
// 可以自定义方法
List<User> selectByAgeGreaterThan(@Param("age") Integer age);
}
3.2 自定义 SQL
public interface UserMapper extends BaseMapper<User> {
// 使用注解方式
@Select("SELECT * FROM user WHERE age > #{age}")
List<User> selectByAge(@Param("age") Integer age);
// 使用 XML 方式(推荐复杂 SQL)
List<User> selectComplexQuery(UserQuery query);
}
对应的 XML:
<!-- resources/mapper/UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rongx.reggie.mapper.UserMapper">
<select id="selectComplexQuery" resultType="com.rongx.reggie.entity.User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="minAge != null">
AND age >= #{minAge}
</if>
<if test="maxAge != null">
AND age <= #{maxAge}
</if>
</where>
ORDER BY create_time DESC
</select>
</mapper>
4. Service 层
4.1 基础 Service
import com.baomidou.mybatisplus.extension.service.IService;
// 服务接口继承 IService
public interface UserService extends IService<User> {
// 自定义业务方法
boolean register(User user);
User login(String username, String password);
}
// 实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public boolean register(User user) {
// 检查用户名是否已存在
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, user.getUsername());
User existing = getOne(wrapper);
if (existing != null) {
throw new BusinessException("用户名已存在");
}
// 密码加密等业务逻辑
user.setPassword(encodePassword(user.getPassword()));
return save(user);
}
@Override
public User login(String username, String password) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, username);
User user = getOne(wrapper);
if (user == null || !verifyPassword(password, user.getPassword())) {
throw new BusinessException("用户名或密码错误");
}
return user;
}
private String encodePassword(String password) {
// 密码加密逻辑
return password; // 实际使用 BCrypt 等加密
}
private boolean verifyPassword(String input, String encoded) {
// 密码验证逻辑
return input.equals(encoded);
}
}
5. 核心 CRUD 操作
5.1 查询操作
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 1. 根据ID查询
public User getById(Long id) {
return userMapper.selectById(id);
}
// 2. 查询所有
public List<User> getAll() {
return userMapper.selectList(null);
}
// 3. 条件查询
public List<User> getByCondition(String username, Integer minAge) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.isNotBlank(username), User::getUsername, username)
.ge(minAge != null, User::getAge, minAge)
.orderByDesc(User::getCreateTime);
return userMapper.selectList(wrapper);
}
// 4. 分页查询
public Page<User> getPage(int current, int size, String keyword) {
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
.or()
.like(StringUtils.isNotBlank(keyword), User::getEmail, keyword);
return userMapper.selectPage(page, wrapper);
}
// 5. 统计查询
public long countByAge(Integer age) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(age != null, User::getAge, age);
return userMapper.selectCount(wrapper);
}
}
5.2 新增操作
public class UserService {
// 1. 插入一条记录
public boolean saveUser(User user) {
return userMapper.insert(user) > 0;
}
// 2. 批量插入
public boolean saveBatch(List<User> users) {
return userMapper.insertBatchSomeColumn(users) > 0; // 需要配置注入器
}
// 3. 插入或更新
public boolean saveOrUpdate(User user) {
return userMapper.insertOrUpdate(user) > 0;
}
}
5.3 更新操作
public class UserService {
// 1. 根据ID更新
public boolean updateById(User user) {
return userMapper.updateById(user) > 0;
}
// 2. 条件更新
public boolean updateByCondition(User user) {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getUsername, user.getUsername())
.set(User::getAge, user.getAge())
.set(User::getEmail, user.getEmail());
return userMapper.update(null, wrapper) > 0;
}
// 3. 字段自增/自减
public boolean incrementAge(Long userId) {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getId, userId)
.setSql("age = age + 1");
return userMapper.update(null, wrapper) > 0;
}
}
5.4 删除操作
public class UserService {
// 1. 根据ID删除
public boolean removeById(Long id) {
return userMapper.deleteById(id) > 0;
}
// 2. 条件删除
public boolean removeByCondition(String username) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, username);
return userMapper.delete(wrapper) > 0;
}
// 3. 批量删除
public boolean removeByIds(List<Long> ids) {
return userMapper.deleteBatchIds(ids) > 0;
}
// 4. 逻辑删除(需要配置逻辑删除字段)
public boolean logicRemoveById(Long id) {
return userMapper.deleteById(id) > 0; // 自动转为逻辑删除
}
}
6. 条件构造器详解
6.1 LambdaQueryWrapper
public void queryExamples() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 等值查询
wrapper.eq(User::getUsername, "admin");
// 不等查询
wrapper.ne(User::getStatus, 0);
// 大于、小于
wrapper.gt(User::getAge, 18)
.lt(User::getAge, 60);
// 范围查询
wrapper.between(User::getAge, 20, 30);
// 模糊查询
wrapper.like(User::getUsername, "张")
.likeLeft(User::getEmail, "@gmail.com") // %@gmail.com
.likeRight(User::getPhone, "138"); // 138%
// IN 查询
wrapper.in(User::getRole, Arrays.asList("admin", "user"));
// 空值判断
wrapper.isNull(User::getDeleteTime)
.isNotNull(User::getUpdateTime);
// 分组和排序
wrapper.groupBy(User::getDeptId)
.orderByAsc(User::getAge)
.orderByDesc(User::getCreateTime);
// 分页
wrapper.last("LIMIT 10");
List<User> users = userMapper.selectList(wrapper);
}
6.2 LambdaUpdateWrapper
public void updateExamples() {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
// 设置更新字段
wrapper.set(User::getAge, 25)
.set(User::getEmail, "new@email.com");
// 条件更新
wrapper.eq(User::getId, 1L);
// SQL 表达式
wrapper.setSql("balance = balance + 100");
userMapper.update(null, wrapper);
}
7. 分页查询
7.1 配置分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInterceptor.setMaxLimit(1000L); // 单页分页条数限制
paginationInterceptor.setOverflow(true); // 页码超出后处理
interceptor.addInnerInterceptor(paginationInterceptor);
// 乐观锁插件(可选)
OptimisticLockerInnerInterceptor optimisticLockerInterceptor = new OptimisticLockerInnerInterceptor();
interceptor.addInnerInterceptor(optimisticLockerInterceptor);
return interceptor;
}
}
7.2 分页使用
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/page")
public R<Page<User>> getPage(
@RequestParam(defaultValue = "1") int current,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String keyword) {
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(keyword)) {
wrapper.like(User::getUsername, keyword)
.or()
.like(User::getEmail, keyword);
}
Page<User> result = userService.page(page, wrapper);
return R.success(result);
}
}
8. 自动填充功能
8.1 实现 MetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "createUser", Long.class, getCurrentUserId());
this.strictInsertFill(metaObject, "updateUser", Long.class, getCurrentUserId());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateUser", Long.class, getCurrentUserId());
}
private Long getCurrentUserId() {
// 从安全上下文获取当前用户ID
// 例如:return SecurityUtils.getCurrentUserId();
return 1L; // 示例
}
}
9. 代码生成器
9.1 快速生成代码
public class CodeGenerator {
public static void main(String[] args) {
// 代码生成器
AutoGenerator generator = new AutoGenerator();
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
globalConfig.setOutputDir(projectPath + "/src/main/java");
globalConfig.setAuthor("rongx");
globalConfig.setOpen(false);
globalConfig.setSwagger2(true);
generator.setGlobalConfig(globalConfig);
// 数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/reggie?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
generator.setDataSource(dataSourceConfig);
// 包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.rongx.reggie");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setController("controller");
generator.setPackageInfo(packageConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude("user", "order", "product"); // 要生成的表
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix("t_"); // 表前缀
generator.setStrategy(strategy);
// 模板配置
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null); // 不生成 XML,使用注解方式
generator.setTemplate(templateConfig);
// 执行生成
generator.execute();
}
}
10. 完整示例项目结构
src/main/java/com/rongx/reggie/
├── entity/ # 实体类
│ ├── User.java
│ └── Product.java
├── mapper/ # Mapper 接口
│ ├── UserMapper.java
│ └── ProductMapper.java
├── service/ # Service 接口
│ ├── UserService.java
│ └── ProductService.java
├── service/impl/ # Service 实现
│ ├── UserServiceImpl.java
│ └── ProductServiceImpl.java
├── controller/ # 控制器
│ ├── UserController.java
│ └── ProductController.java
└── config/ # 配置类
├── MybatisPlusConfig.java
└── MyMetaObjectHandler.java
11. 常用注解总结
| 注解 | 作用 | 示例 |
|---|---|---|
@TableName | 指定表名 | @TableName("user") |
@TableId | 主键注解 | @TableId(type = IdType.AUTO) |
@TableField | 字段注解 | @TableField(fill = FieldFill.INSERT) |
@TableLogic | 逻辑删除 | @TableLogic |
@Version | 乐观锁 | @Version |
@EnumValue | 枚举值 | @EnumValue |
12. 最佳实践
- 使用 Lambda 表达式:避免字段名硬编码
- 合理使用 Service 层:业务逻辑放在 Service
- 配置合理的插件:分页、乐观锁等
- 统一异常处理:处理 MyBatis Plus 异常
- 性能优化:合理使用索引,避免 N+1 查询
MyBatis Plus 大大简化了数据库操作,通过合理使用可以显著提高开发效率。
MyBatis Plus 使用全解析
1428

被折叠的 条评论
为什么被折叠?



