前言
MyBatis-Plus 是在 MyBatis 基础上的增强工具,简化了 CRUD 操作,提供了强大的单表操作能力。本文将介绍 Spring Boot 集成 MyBatis-Plus 的完整用法。
快速开始
1. 添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
2. 配置数据库
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 30000
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
3. 创建实体类
package com.example.demo.entity;
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 email;
private Integer age;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
}
4. 创建 Mapper
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 继承 BaseMapper,自动获得 CRUD 方法
}
5. 创建 Service
package com.example.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;
public interface UserService extends IService<User> {
// 继承 IService,自动获得 CRUD 方法
}
6. 实现 Service
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 实现类,可使用所有 CRUD 方法
}
CRUD 操作
1. 新增
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public UserDTO create(UserCreateDTO dto) {
User user = new User();
user.setUsername(dto.getUsername());
user.setEmail(dto.getEmail());
user.setAge(dto.getAge());
// 插入
boolean success = save(user);
return convertToDTO(user);
}
/**
* 批量插入
*/
public boolean batchInsert(List<User> users) {
return saveBatch(users, 100); // 每批 100 条
}
}
2. 删除
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
/**
* 根据 ID 删除
*/
public boolean deleteById(Long id) {
return removeById(id);
}
/**
* 批量删除
*/
public boolean deleteByIds(List<Long> ids) {
return removeByIds(ids);
}
/**
* 条件删除
*/
public boolean deleteByCondition(String email) {
return remove(new LambdaQueryWrapper<User>()
.eq(User::getEmail, email));
}
}
3. 修改
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
/**
* 根据 ID 更新
*/
public UserDTO update(Long id, UserUpdateDTO dto) {
User user = getById(id);
if (user == null) {
throw BusinessException.notFound("用户");
}
user.setUsername(dto.getUsername());
user.setEmail(dto.getEmail());
boolean success = updateById(user);
return convertToDTO(user);
}
/**
* 根据条件更新
*/
public boolean updateByCondition(UserUpdateDTO dto) {
User user = new User();
user.setAge(dto.getAge());
return update(user, new LambdaQueryWrapper<User>()
.eq(User::getAge, dto.getOldAge()));
}
}
4. 查询
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
/**
* 根据 ID 查询
*/
public UserDTO findById(Long id) {
User user = getById(id);
return convertToDTO(user);
}
/**
* 查询列表
*/
public List<UserDTO> findAll() {
return list().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
/**
* 条件查询
*/
public List<UserDTO> findByCondition(String username, Integer minAge) {
return list(new LambdaQueryWrapper<User>()
.like(StringUtils.isNotBlank(username), User::getUsername, username)
.ge(minAge != null, User::getAge, minAge));
}
}
分页查询
1. 配置分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2. 分页查询
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
/**
* 简单分页
*/
public Page<UserDTO> pageQuery(int page, int size) {
Page<User> userPage = new Page<>(page, size);
Page<User> result = page(userPage);
return convertToDTOPage(result);
}
/**
* 条件分页
*/
public Page<UserDTO> pageQueryCondition(PageQueryDTO query) {
Page<User> userPage = new Page<>(query.getPage(), query.getSize());
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.like(StringUtils.isNotBlank(query.getUsername()), User::getUsername, query.getUsername())
.ge(query.getMinAge() != null, User::getAge, query.getMinAge())
.le(query.getMaxAge() != null, User::getAge, query.getMaxAge())
.orderByDesc(User::getCreateTime);
Page<User> result = page(userPage, wrapper);
return convertToDTOPage(result);
}
/**
* 自定义分页
*/
public Page<UserDTO> pageCustom(PageQueryDTO query) {
Page<UserDTO> page = new Page<>(query.getPage(), query.getSize());
return baseMapper.selectPageCustom(page, query);
}
}
3. Mapper 自定义分页
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT * FROM user ${ew.customSqlSegment}")
Page<UserDTO> selectPageCustom(Page<UserDTO> page, @Param("ew") Wrapper<User> wrapper);
}
常用插件
1. 乐观锁插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
@Data
@TableName("user")
public class User {
@TableId
private Long id;
private String username;
@Version
private Integer version; // 乐观锁版本号
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
public boolean updateWithOptimisticLock(User user) {
// 自动比较版本号
return updateById(user);
}
}
2. 数据权限插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 数据权限插件
interceptor.addInnerInterceptor(new DataPermissionInnerInterceptor(
(sql, mappedStatementId, parameter, boundSql) -> {
// 添加数据权限过滤
return sql + " AND dept_id = 1";
}
));
return interceptor;
}
}
3. 动态表名插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableName = new DynamicTableNameInnerInterceptor();
dynamicTableName.setTableNameHandler((sql, tableName) -> {
if ("user".equals(tableName)) {
String year = "_2024"; // 动态获取
return tableName + year;
}
return tableName;
});
interceptor.addInnerInterceptor(dynamicTableName);
return interceptor;
}
}
代码生成器
1. 添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
2. 配置生成器
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create(
"jdbc:mysql://localhost:3306/demo",
"root",
"123456"
)
.globalConfig(builder -> {
builder.author("zhangsan")
.outputDir("src/main/java")
.disableOpenDir()
.commentDate("yyyy-MM-dd");
})
.packageConfig(builder -> {
builder.parent("com.example.demo")
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.controller("controller");
})
.strategyConfig(builder -> {
builder.addInclude("user", "order", "product")
.entityBuilder()
.enableLombok()
.enableTableFieldAnnotation()
.mapperBuilder()
.enableMapperAnnotation()
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.controllerBuilder()
.enableRestStyle();
})
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
}
最佳实践
1. 逻辑删除
@Data
@TableName("user")
public class User {
@TableId
private Long id;
private String username;
@TableLogic
private Integer deleted; // 0-未删除,1-已删除
}
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
2. 自动填充
@Data
@TableName("user")
public class User {
@TableId
private Long id;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
}
}
3. 防止全表更新
mybatis-plus:
global-config:
db-config:
# 禁止全表更新
enable-update-batch: false
总结
MyBatis-Plus 要点:
- ✅ CRUD - BaseMapper、IService
- ✅ 分页 - PaginationInnerInterceptor
- ✅ 插件 - 乐观锁、数据权限、动态表名
- ✅ 代码生成 - FastAutoGenerator
- ✅ 最佳实践 - 逻辑删除、自动填充
MyBatis-Plus 让单表操作变得简单高效。