MyBatis-Plus复习
一、MyBatis-Plus 基础介绍
1.1 框架简介
MyBatis 是单表增删改查需要重复编写大量 XML 与 SQL,MyBatis-Plus 在 MyBatis 基础上做无侵入增强,无需修改原有 MyBatis 代码即可接入,一键实现单表全部数据库操作,大幅提升开发效率。
- 复杂关联:自定义 Mapper XML 编写原生关联 SQL;
- 简单关联:Service 层多次单表查询,业务组装数据。
1.2 底层执行流程
- SpringBoot 启动扫描实体类;
- 反射读取
@TableName、@TableId等注解,解析表名、字段、主键、逻辑删除标识; - 自动生成 insert/update/delete/select 标准 SQL 注入 MyBatis 容器;
- 开发者直接调用 BaseMapper 内置方法完成数据库交互。
二、SpringBoot 快速整合 MyBatis-Plus 实战
2.1 环境准备
JDK8+、SpringBoot2.x、MySQL8.0、Maven 项目
2.2 数据库表初始化
sql
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL COMMENT '姓名',
age INT NULL COMMENT '年龄',
email VARCHAR(50) NULL COMMENT '邮箱',
deleted INT DEFAULT 0 COMMENT '逻辑删除标记',
version INT DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com');
2.3 Maven 核心依赖
xml
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok简化实体类 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- MyBatis-Plus启动器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
注意:不可同时引入原生 MyBatis 依赖,会造成冲突。
2.4 application.yml 配置
yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/boot?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印执行SQL
global-config:
db-config:
id-type: assign_id # 默认雪花算法主键
logic-delete-field: deleted
logic-delete-value: 1 # 已删除
logic-not-delete-value: 0 # 正常
mapper-locations: classpath:mapper/*.xml # 自定义XML路径
2.5 实体类编写
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic
private Integer deleted;
@Version
private Integer version;
}
2.6 Mapper 接口与启动类
Mapper 继承BaseMapper自动获得全部 CRUD 方法:
@Mapper
public interface UserMapper extends BaseMapper<User> {}
启动类使用@MapperScan统一扫描 Mapper,无需每个接口加@Mapper:
@SpringBootApplication
@MapperScan("com.mp.mapper")
public class MpApplication {
public static void main(String[] args) {
SpringApplication.run(MpApplication.class, args);
}
}
2.7 基础测试查询
@SpringBootTest
class MpTest {
@Autowired
private UserMapper userMapper;
@Test
void testSelectAll(){
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
}
}
运行控制台输出完整 SQL,查询全部数据,基础环境搭建完成。
三、MyBatis-Plus 核心注解详解
3.1 @TableName
绑定实体与数据库表,实体类名和表名不一致时必须使用,核心属性 value 指定表名。
3.2 @TableId 主键注解
标记主键字段,type 控制主键生成策略,局部注解优先级高于全局配置:
- AUTO:数据库自增,适合单体项目;
- ASSIGN_ID:雪花算法,Long/String 类型,分布式推荐默认策略;
- ASSIGN_UUID:32 位 UUID 字符串;
- INPUT:手动传入主键;
- NONE:跟随全局配置。
雪花算法原理:1 位符号位 + 41 位时间戳 + 10 位机器 ID+12 位序列号,分布式全局唯一。
3.3 @TableField
普通字段注解,常用场景:
- value:实体属性与数据库字段名不一致时映射;
- exist=false:标记该属性不属于数据库字段;
- select=false:查询时不返回该字段;
- fill:自动填充(INSERT/UPDATE/INSERT_UPDATE)。
3.4 @TableLogic
逻辑删除字段标记,开启后所有查询自动拼接where deleted=0,delete 操作转为 update 更新删除标记,避免数据物理丢失。
3.5 @Version
乐观锁版本号注解,用于并发更新,更新时自动携带版本条件,防止数据覆盖丢失。
四、BaseMapper 通用 CRUD 操作
4.1 新增 insert ()
插入实体,使用雪花算法自动生成 ID 并回填至实体对象:
@Test
void testInsert(){
User user = new User();
user.setName("张三");
user.setAge(22);
user.setEmail("zs@qq.com");
int rows = userMapper.insert(user);
System.out.println("受影响行数:"+rows);
System.out.println("自动生成ID:"+user.getId());
}
4.2 更新操作
- updateById:根据主键更新实体非 null 字段;
User user = new User();
user.setId(1L);
user.setName("张三修改");
userMapper.updateById(user);
- update (entity, wrapper):自定义条件批量更新数据。
4.3 查询常用方法
// 根据主键单查
User user = userMapper.selectById(1L);
// 批量ID查询
List<User> list = userMapper.selectBatchIds(Arrays.asList(1,2));
// Map等值多条件查询
Map<String,Object> map = new HashMap<>();
map.put("name","Jack");
List<User> userList = userMapper.selectByMap(map);
// 查询总条数
Integer total = userMapper.selectCount(null);
4.4 删除操作
- 物理删除(未开启逻辑删除):deleteById、deleteBatchIds、deleteByMap;
- 逻辑删除(全局配置 +@TableLogic):执行 deleteById 不会删除数据,SQL 变为
update user set deleted=1 where id=? and deleted=0。
五、条件构造器 Wrapper(复杂查询核心)
Wrapper 分为四类,企业开发优先使用 Lambda 系列,杜绝字段硬编码:
- QueryWrapper:普通字符串条件查询;
- LambdaQueryWrapper:Lambda 表达式查询(推荐);
- UpdateWrapper:自定义更新条件;
- LambdaUpdateWrapper:Lambda 更新条件。
常用查询示例
// 1. 普通Wrapper:年龄20~30,姓名不为空
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name").between("age",20,30).orderByDesc("id");
List<User> list = userMapper.selectList(wrapper);
// 2. LambdaWrapper(无硬编码,推荐)
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.ge(User::getAge, 20).likeRight(User::getEmail, "t");
List<User> lambdaList = userMapper.selectList(lambdaWrapper);
常用方法:eq 等于、ne 不等于、gt 大于、ge 大于等于、lt 小于、le 小于等于、between 区间、like 模糊查询、orderByDesc 倒序。
六、分页插件
MP 内置物理分页,无需引入 PageHelper,只需配置拦截器。
6.1 分页配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// MySQL分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
6.2 分页代码使用
@Test
void testPage(){
// 参数1:当前页码,参数2:每页条数
Page<User> page = new Page<>(1,2);
Page<User> pageResult = userMapper.selectPage(page, null);
// 分页数据
List<User> records = pageResult.getRecords();
// 分页信息
System.out.println("总条数:"+pageResult.getTotal());
System.out.println("总页数:"+pageResult.getPages());
System.out.println("是否下一页:"+pageResult.hasNext());
}
底层自动执行两条 SQL:count 统计总数 + limit 分页查询。
七、乐观锁解决并发更新丢失
7.1 使用场景
多线程同时修改同一条数据,无锁会出现后提交的数据覆盖先提交数据,造成数据丢失。乐观锁通过 version 版本号实现无锁并发控制。
7.2 完整实现
- 数据库添加 version 字段,默认值 0;
- 实体 version 字段添加
@Version; - 拦截器添加乐观锁插件:
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
- 并发测试逻辑:
// 两个线程读取同一条数据
Product p1 = productMapper.selectById(1L);
Product p2 = productMapper.selectById(1L);
// 线程1更新成功,version自增1
p1.setPrice(p1.getPrice()+500);
productMapper.updateById(p1);
// 线程2携带旧version更新,匹配不到数据,更新行数为0,更新失败
p2.setPrice(p2.getPrice()-300);
int rows = productMapper.updateById(p2);
if(rows == 0){
// 业务重试:重新查询最新数据再更新
}
自动生成更新 SQL:update product set price=?,version=version+1 where id=? and version=?。
八、Service 层通用封装 IService
MP 在 Mapper 之上封装业务层通用接口,命名区分 Mapper:Mapper 用 select/insert,Service 用 list/get/save/remove。
8.1 代码结构
// Service接口
public interface UserService extends IService<User> {}
// 实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
8.2 Service 常用方法
@Autowired
private UserService userService;
userService.save(user); // 新增
userService.saveBatch(list); // 批量新增
User user = userService.getById(1L); // 根据id查询
List<User> list = userService.list(wrapper); // 条件查询
IPage<User> page = userService.page(new Page<>(1,5), wrapper); // 分页查询
userService.saveOrUpdate(user); // 存在更新,不存在新增
九、自定义 SQL 处理复杂多表查询
单表操作使用 MP 内置方法,多表联查、复杂聚合 SQL 兼容原生 MyBatis XML。
- Mapper 接口定义自定义方法
public interface UserMapper extends BaseMapper<User> {
List<User> selectByAge(Integer age);
}
- resources/mapper 下创建 UserMapper.xml
xml
<mapper namespace="com.mp.mapper.UserMapper">
<select id="selectByAge" resultType="com.mp.pojo.User">
select * from user where age = #{age}
</select>
</mapper>
十、代码生成器 AutoGenerator
一键生成 controller、service、mapper、entity 全套代码,大幅减少重复编码。
10.1 新增依赖
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
10.2 核心生成工具类
public class MpGenerator {
// 数据源配置
public static DataSourceConfig dataSource(){
DataSourceConfig ds = new DataSourceConfig();
ds.setDbType(DbType.MYSQL);
ds.setUrl("jdbc:mysql:///boot?serverTimezone=Asia/Shanghai");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
// 全局配置
public static GlobalConfig globalConfig(){
GlobalConfig gc = new GlobalConfig();
String path = System.getProperty("user.dir");
gc.setOutputDir(path+"/src/main/java");
gc.setAuthor("作者");
gc.setServiceName("%sService");
return gc;
}
// 包配置
public static PackageConfig packageConfig(){
PackageConfig pc = new PackageConfig();
pc.setParent("com.mp");
pc.setController("controller");
pc.setService("service");
pc.setMapper("mapper");
pc.setEntity("pojo");
return pc;
}
// 策略配置
public static StrategyConfig strategy(){
StrategyConfig sc = new StrategyConfig();
sc.setEntityLombokModel(true);
sc.setLogicDeleteFieldName("deleted");
sc.setVersionFieldName("version");
sc.setNaming(NamingStrategy.underline_to_camel);
sc.setInclude("user"); // 指定生成表
return sc;
}
public static void main(String[] args) {
AutoGenerator ag = new AutoGenerator();
ag.setDataSource(dataSource());
ag.setGlobalConfig(globalConfig());
ag.setPackageInfo(packageConfig());
ag.setStrategy(strategy());
ag.execute();
}
}
运行 main 方法自动生成整套分层代码。
更多推荐

所有评论(0)