MyBatis是一款优秀的半自动化ORM框架,通过XML或注解将SQL与Java对象映射,和新特性包括:
痛点:需手动编写大量基础CRUD代码,复杂查询需手写XML,开发效率受限。
MyBatis-Plus(简称MP)在MyBatis基础上进行增强,核心特性如下:
特性 | 说明 |
---|---|
无侵入增强 | 通过继承 BaseMapper 即可获得通用 CRUD 方法,无需修改 MyBatis 原生配置。 |
条件构造器 | 提供 QueryWrapper 和 LambdaQueryWrapper ,支持链式调用动态构建查询条件。 |
代码生成器 | 自动生成 Entity、Mapper、Service、Controller 层代码,支持自定义模板。 |
分页插件 | 支持物理分页,自动适配不同数据库方言(MySQL、Oracle 等)。 |
主键策略 | 内置雪花算法、UUID、自增等多种分布式 ID 生成方案。 |
ActiveRecord模式 | 实体类继承 Model 可直接操作数据库,简化 DAO 层代码。 |
SQL注入器 | 支持自定义全局方法(如逻辑删除、批量插入)。 |
性能分析插件 | 输出SQL执行时间,帮助识别慢查询。 |
@TableName
、@TableField
等注解实现ORM映射,告别XML配置的繁琐。// Lambda 示例(防止字段名拼写错误)
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "John").ge(User::getAge, 18);
Page page = new Page<>(1, 10); // 第1页,每页10条
userMapper.selectPage(page, wrapper);
User user = new User().selectById(1L);
user.setName("Alice").updateById();
动态Mapper代理
条件构造器解析
创建测试表:在MySQL中创建测试表user
CREATE TABLE user (
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
age INT(11) DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
deleted TINYINT(1) DEFAULT 0 COMMENT '逻辑删除标记',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
搭建项目引入依赖:在 pom.xml
中添加 Spring Boot 和 MyBatis-Plus 依赖
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-boot-starter
3.5.3.1
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
创建实体类User.java,使用MyBatis-Plus注解:
@Data
@TableName("user") // 指定表名(默认类名驼峰转下划线)
public class User {
@TableId(type = IdType.AUTO) // 主键自增策略
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic // 逻辑删除标记
private Integer deleted;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入/更新时自动填充
private LocalDateTime updateTime;
}
创建Mapper接口继承BaseMapper:
@Mapper
public interface UserMapper extends BaseMapper {
// 无需编写 XML,自动继承通用 CRUD 方法
}
application.yml配置数据源和MyBatis-Plus
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志
global-config:
db-config:
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
启动类添加@MapperScan注解扫描Mapper接口:
@SpringBootApplication
@MapperScan("com.example.mapper") // 指定 Mapper 接口包路径
public class MybatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusDemoApplication.class, args);
}
/**
* 配置分页插件(必选)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
编写JUnit测试类验证CRUD功能
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/**
* 测试插入
*/
@Test
public void testInsert() {
User user = new User();
user.setName("John");
user.setAge(28);
user.setEmail("[email protected]");
int rows = userMapper.insert(user);
System.out.println("插入记录数:" + rows);
}
/**
* 测试分页查询
*/
@Test
public void testSelectPage() {
Page page = new Page<>(1, 2); // 第1页,每页2条
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.like("name", "J");
IPage userPage = userMapper.selectPage(page, wrapper);
userPage.getRecords().forEach(System.out::println);
}
/**
* 测试逻辑删除
*/
@Test
public void testLogicDelete() {
int rows = userMapper.deleteById(1L);
System.out.println("逻辑删除记录数:" + rows);
}
}
BaseMapper
提供开箱即用的通用 CRUD 方法,无需编写 SQL 或 XML。
// 插入(返回影响行数)
int insert(User user);
// 按 ID 查询
User selectById(Long id);
// 按条件查询(返回一条记录)
User selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper);
// 按条件批量查询
List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
// 按条件更新
int update(@Param(Constants.ENTITY) User entity,
@Param(Constants.WRAPPER) Wrapper updateWrapper);
// 按 ID 删除
int deleteById(Serializable id);
方法分类:
eq
, ne
, gt
, ge
, lt
, le
, between
, like
and
, or
, nested
groupBy
, orderByAsc
, orderByDesc
inSql
, exists
, notExists
基础使用示例:
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("age", 25)
.like("name", "张")
.between("create_time", "2023-01-01", "2023-12-31");
List users = userMapper.selectList(wrapper);
子查询:
wrapper.inSql("id", "SELECT id FROM user WHERE age > 30");
分组与排序:
wrapper.select("COUNT(*) as count", "age")
.groupBy("age")
.orderByDesc("count");
多条件拼接:
wrapper.and(w -> w.eq("status", 1).or().eq("role", "admin"))
.or(w -> w.gt("score", 90));
UpdateWrapper updateWrapper = new UpdateWrapper<>();
updateWrapper.set("email", "[email protected]")
.eq("name", "John");
userMapper.update(null, updateWrapper);
通过Lambda表达式避免硬编码字段名,增强类型安全。
LambdaQueryWrapper lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(User::getAge, 25)
.like(User::getName, "张");
LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.set(User::getEmail, "[email protected]")
.eq(User::getId, 1L);
在配置类中注册分页插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
// 分页参数:当前页、每页条数
Page page = new Page<>(1, 10);
// 条件构造
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.ge("age", 18);
// 执行分页查询
IPage userPage = userMapper.selectPage(page, wrapper);
// 获取结果
List records = userPage.getRecords(); // 当前页数据
long total = userPage.getTotal(); // 总记录数
ServiceImpl, T>
:默认实现类。public interface UserService extends IService {
// 自定义扩展方法
}
@Service
public class UserServiceImpl extends ServiceImpl implements UserService {
}
// 使用示例
userService.saveBatch(userList); // 批量插入
userService.lambdaUpdate()
.set(User::getEmail, "[email protected]")
.eq(User::getAge, 25)
.update(); // Lambda 更新
public enum IdType {
AUTO, // 数据库自增
NONE, // 无策略
INPUT, // 手动输入
ASSIGN_ID, // 雪花算法
ASSIGN_UUID // UUID
}
public enum FieldFill {
DEFAULT, // 不填充
INSERT, // 插入时填充
UPDATE, // 更新时填充
INSERT_UPDATE // 插入和更新时填充
}
在Mapper接口中定义方法,并在XML中编写复杂SQL:
// UserMapper.java
List selectComplexUsers(@Param("role") String role);
// UserMapper.xml
实体类继承Model
public class User extends Model {
// ... 字段定义
}
// 直接操作实体
User user = new User();
user.setName("Alice");
user.insert(); // 插入
User result = user.selectById(1L); // 查询
快速 CRUD 开发:适用于后台管理系统、基础数据模块,减少重复代码。
复杂动态查询:通过 Wrapper 动态构建查询条件,替代手写 XML 中的
标签。
分页标准化:统一分页逻辑,避免各业务模块独立实现分页。
微服务环境:雪花算法生成分布式 ID,适应高并发、分布式部署场景。