MyBatis-Plus复习
2026/7/5 3:08:11 网站建设 项目流程

一、MyBatis-Plus 基础介绍

1.1 框架简介

MyBatis 是单表增删改查需要重复编写大量 XML 与 SQL,MyBatis-Plus 在 MyBatis 基础上做无侵入增强,无需修改原有 MyBatis 代码即可接入,一键实现单表全部数据库操作,大幅提升开发效率。

  1. 复杂关联:自定义 Mapper XML 编写原生关联 SQL;
  2. 简单关联:Service 层多次单表查询,业务组装数据。

1.2 底层执行流程

  1. SpringBoot 启动扫描实体类;
  2. 反射读取@TableName@TableId等注解,解析表名、字段、主键、逻辑删除标识;
  3. 自动生成 insert/update/delete/select 标准 SQL 注入 MyBatis 容器;
  4. 开发者直接调用 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 控制主键生成策略,局部注解优先级高于全局配置:

  1. AUTO:数据库自增,适合单体项目;
  2. ASSIGN_ID:雪花算法,Long/String 类型,分布式推荐默认策略;
  3. ASSIGN_UUID:32 位 UUID 字符串;
  4. INPUT:手动传入主键;
  5. NONE:跟随全局配置。

雪花算法原理:1 位符号位 + 41 位时间戳 + 10 位机器 ID+12 位序列号,分布式全局唯一。

3.3 @TableField

普通字段注解,常用场景:

  1. value:实体属性与数据库字段名不一致时映射;
  2. exist=false:标记该属性不属于数据库字段;
  3. select=false:查询时不返回该字段;
  4. 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 更新操作

  1. updateById:根据主键更新实体非 null 字段;
User user = new User(); user.setId(1L); user.setName("张三修改"); userMapper.updateById(user);
  1. 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 删除操作

  1. 物理删除(未开启逻辑删除):deleteById、deleteBatchIds、deleteByMap;
  2. 逻辑删除(全局配置 +@TableLogic):执行 deleteById 不会删除数据,SQL 变为update user set deleted=1 where id=? and deleted=0

五、条件构造器 Wrapper(复杂查询核心)

Wrapper 分为四类,企业开发优先使用 Lambda 系列,杜绝字段硬编码:

  1. QueryWrapper:普通字符串条件查询;
  2. LambdaQueryWrapper:Lambda 表达式查询(推荐);
  3. UpdateWrapper:自定义更新条件;
  4. 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 完整实现

  1. 数据库添加 version 字段,默认值 0;
  2. 实体 version 字段添加@Version
  3. 拦截器添加乐观锁插件:
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  1. 并发测试逻辑:
// 两个线程读取同一条数据 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。

  1. Mapper 接口定义自定义方法
public interface UserMapper extends BaseMapper<User> { List<User> selectByAge(Integer age); }
  1. 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 方法自动生成整套分层代码。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询