IT评测·应用市场-qidao123.com技术社区

标题: MyBatis-Plus 从入门到醒目教学文档 [打印本页]

作者: 祗疼妳一个    时间: 2025-4-1 02:09
标题: MyBatis-Plus 从入门到醒目教学文档
一、弁言

MyBatis-Plus 是一个在 MyBatis 基础上进行增强的工具,它在保留 MyBatis 原有功能的同时,极大地简化了开辟流程,进步了开辟效率。本教学文档旨在帮助开辟者全面把握 MyBatis-Plus,从基础入门到醒目其焦点、扩展及插件功能,让开辟者能够熟练运用它进行高效的数据库操纵开辟。
二、快速入门

2.1 入门案例

2.1.1 需求

基于给定项目,实现新增用户、根据 id 查询用户、根据 id 批量查询用户、根据 id 更新用户、根据 id 删除用户的功能。
2.1.2 步骤

  1. <dependency>
  2.     <groupId>com.baomidou</groupId>
  3.     <artifactId>mybatis-plus-boot-starter</artifactId>
  4.     <version>3.5.3.1</version>
  5. </dependency>
复制代码
  1. public interface UserMapper extends BaseMapper<User> {
  2. }
复制代码
BaseMapper接口提供了丰富的 CRUD 方法,如insert(新增)、updateById(根据 id 更新)、selectById(根据 id 查询)、deleteById(根据 id 删除)等,涵盖了基本的数据库操纵。
2.2 常见注解

2.3 常见配置

MyBatis-Plus 的配置项继续了 MyBatis 原生配置并增加了一些特有配置。在application.yml文件中常见配置如下:
  1. mybatis-plus:
  2.   type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
  3.   mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,默认值
  4.   configuration:
  5.     map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射
  6.     cache-enabled: false # 是否开启二级缓存
  7.   global-config:
  8.     db-config:
  9.       id-type: assign_id # id为雪花算法生成
  10.       update-strategy: not_null # 更新策略:只更新非空字段
复制代码

2.4 总结

MyBatis-Plus 利用的基本流程:
三、焦点功能

3.1 条件构造器

3.1.1 功能先容

MyBatis-Plus 支持各种复杂的where条件,QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分;UpdateWrapper和LambdaUpdateWrapper通常在set语句比较特殊时利用。尽量利用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码。
3.1.2 案例

  1. QueryWrapper<User> wrapper = new QueryWrapper<>();
  2. wrapper.like("username", "o").ge("balance", 1000);
  3. List<User> userList = userMapper.selectList(wrapper);
复制代码
  1. UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
  2. updateWrapper.setSql("balance = balance - 200").in("id", 1, 2, 4);
  3. userMapper.update(null, updateWrapper);
复制代码
3.2 自界说 SQL

3.2.1 实现方式

3.2.2 案例

  1. void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount") int amount);
复制代码
在Mapper.xml文件中编写 SQL:
  1. <update id="updateBalanceByIds">
  2.     UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment}
  3. </update>
复制代码
在测试方法中调用:
  1. List<Long> ids = List.of(1L, 2L, 4L);
  2. int amount = 200;
  3. LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().in(User::getId, ids);
  4. userMapper.updateBalanceByIds(wrapper, amount);
复制代码
  1. List<User> queryUserByIdAndAddr(@Param("ids") List<Long> ids, @Param("city") String city);
复制代码
在Mapper.xml文件中编写 SQL:
  1. <select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">
  2.     SELECT *
  3.     FROM user u
  4.     INNER JOIN address a ON u.id = a.user_id
  5.     WHERE u.id
  6.     <foreach collection="ids" separator="," item="id" open="IN (" close=")">
  7.         #{id}
  8.     </foreach>
  9.     AND a.city = #{city}
  10. </select>
复制代码
3.3 Service 接口

3.3.1 利用流程

  1. public interface IUserService extends IService<User> {
  2.     // 自定义方法声明
  3.     List<User> listByName(String name);
  4. }
  5. public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
  6.     @Override
  7.     public List<User> listByName(String name) {
  8.         // 具体实现逻辑
  9.         QueryWrapper<User> wrapper = new QueryWrapper<>();
  10.         wrapper.like("username", name);
  11.         return list(wrapper);
  12.     }
  13. }
复制代码
3.3.2 案例

  1. @RestController
  2. @RequestMapping("/users")
  3. public class UserController {
  4.     @Autowired
  5.     private IUserService userService;
  6.     @PostMapping
  7.     public void addUser(@RequestBody User user) {
  8.         userService.save(user);
  9.     }
  10.     @DeleteMapping("/{id}")
  11.     public void deleteUser(@PathVariable Long id) {
  12.         userService.removeById(id);
  13.     }
  14.     @GetMapping("/{id}")
  15.     public User getUserById(@PathVariable Long id) {
  16.         return userService.getById(id);
  17.     }
  18.     @GetMapping
  19.     public List<User> listUsersByIds(@RequestParam List<Long> ids) {
  20.         return userService.listByIds(ids);
  21.     }
  22.     @PutMapping("/{id}/deduction/{money}")
  23.     public void deductionBalance(@PathVariable Long id, @PathVariable Integer money) {
  24.         User user = userService.getById(id);
  25.         user.setBalance(user.getBalance() - money);
  26.         userService.updateById(user);
  27.     }
  28. }
复制代码
  1. @Override
  2. public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
  3.     LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
  4.     if (name != null) {
  5.         wrapper.like(User::getUsername, name);
  6.     }
  7.     if (status != null) {
  8.         wrapper.eq(User::getStatus, status);
  9.     }
  10.     if (minBalance != null && maxBalance != null) {
  11.         wrapper.between(User::getBalance, minBalance, maxBalance);
  12.     }
  13.     return list(wrapper);
  14. }
复制代码
  1. @Override
  2. public void updateBalanceById(Long id, Integer money) {
  3.     User user = getById(id);
  4.     if (user == null) {
  5.         throw new RuntimeException("用户不存在");
  6.     }
  7.     if (user.getStatus() == 2) {
  8.         throw new RuntimeException("用户已冻结,无法操作");
  9.     }
  10.     if (user.getBalance() < money) {
  11.         throw new RuntimeException("余额不足");
  12.     }
  13.     user.setBalance(user.getBalance() - money);
  14.     if (user.getBalance() == 0) {
  15.         user.setStatus(2);
  16.     }
  17.     updateById(user);
  18. }
复制代码
  1. @Test
  2. void testBatchInsert() {
  3.     List<User> userList = new ArrayList<>();
  4.     for (int i = 0; i < 100000; i++) {
  5.         User user = new User();
  6.         user.setUsername("user" + i);
  7.         user.setPassword("123456");
  8.         userList.add(user);
  9.     }
  10.     long startTime = System.currentTimeMillis();
  11.     // 普通for循环插入
  12.     for (User user : userList) {
  13.         userService.save(user);
  14.     }
  15.     long endTime = System.currentTimeMillis();
  16.     System.out.println("普通for循环插入耗时:" + (endTime - startTime) + "ms");
  17.     startTime = System.currentTimeMillis();
  18.     // IService的批量插入
  19.     userService.saveBatch(userList);
  20.     endTime = System.currentTimeMillis();
  21.     System.out.println("IService的批量插入耗时:" + (endTime - startTime) + "ms");
  22.     // 开启rewriteBatchedStatements=true参数
  23.     // 在jdbc url中添加rewriteBatchedStatements=true
  24.     startTime = System.currentTimeMillis();
  25.     userService.saveBatch(userList);
  26.     endTime = System.currentTimeMillis();
  27.     System.out.println("开启rewriteBatchedStatements=true参数后批量插入耗时:" + (endTime - startTime) + "ms");
  28. }
复制代码
四、扩展功能

4.1 代码天生

4.1.1 插件安装

在IntelliJ IDEA的Marketplace中搜索并安装MyBatisPlus插件,安装完成后重启IDEA。
4.1.2 代码天生配置

4.2 静态工具

Db类提供了一系列静态方法,用于简化数据库操纵,如save(保存)、removeById(根据 id 删除)、listByIds(根据 id 列表查询)等。例如,改造根据 id 查询用户的接口,查询用户的同时查询出用户对应的所有地点:
  1. @Override
  2. public User getUserWithAddressesById(Long id) {
  3.     User user = Db.getById(User.class, id);
  4.     List<Address> addresses = Db.listByMap(Address.class, Collections.singletonMap("user_id", id));
  5.     user.setAddresses(addresses);
  6.     return user;
  7. }
复制代码
4.3 逻辑删除

4.3.1 实现原理

逻辑删除是基于代码逻辑模拟删除效果,在表中添加一个字段(如deleted)标志数据是否被删除。当删除数据时把标志置为 1,查询时只查询标志为 0 的数据。
4.3.2 配置方法

在application.yaml文件中配置逻辑删除的字段名称和值:
  1. mybatis-plus:
  2.   global-config:
  3.     db-config:
  4.       logic-delete-field: flag # 全局逻辑删除的实体字段名,字段类型可以是boolean、integer
  5.       logic-delete-value: 1 # 逻辑已删除值(默认为1)
  6.       logic-not-delete-value: 0 # 逻辑未删除值(默认为0)
复制代码
在实体类中添加对应的字段:
  1. public class User {
  2.     private Long id;
  3.     // 其他字段
  4.     @TableField("flag")
  5.     private Integer deleted;
  6. }
复制代码
MyBatis-Plus 会自动修改 CRUD 语句,实现逻辑删除功能。但逻辑删除会导致数据库表垃圾数据增多,影响查询效率,SQL 中都须要对逻辑删除字段做判断,因此在某些场景下可考虑将数据迁移到其它表。
4.4 枚举处置处罚器

4.4.1 实现 PO 类中的枚举类型变量与数据库字段的转换

  1. @Getter
  2. public enum UserStatus {
  3.     NORMAL(1, "正常"),
  4.     FREEZE(2, "冻结");
  5.     @EnumValue
  6.     private final int value;
  7.     private final String desc;
  8.     UserStatus(int value, String desc) {
  9.         this.value = value;
  10.         this.desc = desc;
  11.     }
  12. }
复制代码
  1. mybatis-plus:
  2.   configuration:
  3.     default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
复制代码
4.5 JSON 处置处罚器

4.5.1 处置处罚数据库中的 JSON 类型字段

当数据库表中有 JSON 类型字段时,在实体类中利用@TableField(typeHandler = JacksonTypeHandler.class)注解进行处置处罚。例如:
  1. @Data
  2. public class User {
  3.     private Long id;
  4.     private String username;
  5.     @TableField(typeHandler = JacksonTypeHandler.class)
  6.     private UserInfo info;
  7. }
  8. @Data
  9. public class UserInfo {
  10.     private Integer age;
  11.     private String intro;
  12.     private String gender;
  13. }
复制代码
这样在进行数据库操纵时,MyBatis-Plus 会自动处置处罚 JSON 字段的序列化和反序列化。
4.6 配置加密

4.6.1 利用 AES 算法加密配置中的敏感信息

  1. @Test
  2. void contextLoads() {
  3.     // 1.生成16位随机AES密钥
  4.     String randomKey = AES.generateRandomKey();
  5.     System.out.println("randomKey = " + random
复制代码
4.6 配置加密

4.6.1 利用 AES 算法加密配置中的敏感信息

  1. @Test
  2. void contextLoads() {
  3.     // 1.生成16位随机AES密钥
  4.     String randomKey = AES.generateRandomKey();
  5.     System.out.println("randomKey = " + random
  6. Key);    // 2.利用密钥对用户名加密    String username = AES.encrypt("root", randomKey);    System.out.println("username = " + username);    // 3.利用密钥对暗码加密    String password = AES.encrypt("MySQL123", randomKey);    System.out.println("password = " + password);}
复制代码
  1. spring:
  2.   datasource:
  3.     url: jdbc:mysql://127.0.0.1:3306/mp
  4.     driver-class-name: com.mysql.cj.jdbc.Driver
  5.     username: mpw:QWWVnk1Oal3258x5rVhaeQ==
  6.     password: mpw:EUFmeH3cNAzdRGdOQcabWg==
复制代码

五、插件功能

5.1 插件概述

MyBatis-Plus 基于 MyBatis 的 Interceptor 实现了MybatisPlusInterceptor基础拦截器,内部保存了多个内置拦截器集合,这些拦截器可以在 SQL 实行的差别阶段进行干预,实现各种增强功能。
5.2 内置拦截器先容

序号拦截器描述1TenantLineInnerInterceptor多租户插件,用于实现多租户功能,在 SQL 中自动添加租户相关的过滤条件2DynamicTableNameInnerInterceptor动态表名插件,可根据业务需求动态切换表名3PaginationInnerInterceptor分页插件,实现对查询结果的分页功能4OptimisticLockerInnerInterceptor乐观锁插件,用于办理多用户并发操纵时的数据冲突题目5IllegalSQLInnerInterceptorSQL 性能规范插件,检测并拦截不符合性能规范的垃圾 SQL6BlockAttackInnerInterceptor防止全表更新和删除的插件,避免误操纵导致数据大量丢失 5.3 分页插件详细利用

5.3.1 配置分页插件

在配置类中注册 MyBatis-Plus 的焦点插件,并添加分页插件:
  1. @Configuration
  2. public class MybatisConfig {
  3.     @Bean
  4.     public MybatisPlusInterceptor mybatisPlusInterceptor() {
  5.         // 1.初始化核心插件
  6.         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  7.         // 2.添加分页插件
  8.         PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
  9.         pageInterceptor.setMaxLimit(1000L); // 设置分页上限
  10.         interceptor.addInnerInterceptor(pageInterceptor);
  11.         return interceptor;
  12.     }
  13. }
复制代码
5.3.2 利用分页 API

在 Service 接口中,IService提供了分页查询的方法,如page(E page, Wrapper<T> queryWrapper)和page(E page)。在测试方法中利用分页 API 进行查询:
  1. @Test
  2. void testPageQuery() {
  3.     // 1.查询
  4.     int pageNo = 1, pageSize = 5;
  5.     // 1.1.分页参数
  6.     Page<User> page = Page.of(pageNo, pageSize);
  7.     // 1.2.排序参数,通过OrderItem来指定
  8.     page.addOrder(new OrderItem("balance", false));
  9.     // 1.3.分页查询
  10.     Page<User> p = userService.page(page);
  11.     // 2.总条数
  12.     System.out.println("total = " + p.getTotal());
  13.     // 3.总页数
  14.     System.out.println("pages = " + p.getPages());
  15.     // 4.分页数据
  16.     List<User> records = p.getRecords();
  17.     records.forEach(System.out::println);
  18. }
复制代码
5.3.3 分页查询案例

实现一个UserController接口,遵循特定接口规范实现 User 的分页查询。接口规范如下:
参数阐明哀求方式GET哀求路径/users/page哀求参数pageNo(页码,默认 1)、pageSize(每页数量,默认 5)、sortBy(排序字段,默认updateTime)、isAsc(是否升序,默认 true)、name(用户名关键字,可选)、status(用户状态,可选)返回值包罗总条数total、总页数pages、数据列表list的 JSON 对象特殊阐明如果排序字段为空,默认按照更新时间排序;排序字段不为空,则按照排序字段排序
  1. @RestController
  2. @RequestMapping("/users")
  3. public class UserController {
  4.     @Autowired
  5.     private IUserService userService;
  6.     @GetMapping("/page")
  7.     public PageDTO<User> pageQuery(
  8.             @RequestParam(defaultValue = "1") int pageNo,
  9.             @RequestParam(defaultValue = "5") int pageSize,
  10.             @RequestParam(required = false) String sortBy,
  11.             @RequestParam(defaultValue = "true") boolean isAsc,
  12.             @RequestParam(required = false) String name,
  13.             @RequestParam(required = false) Integer status) {
  14.         Page<User> page = new Page<>(pageNo, pageSize);
  15.         LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
  16.         if (name != null) {
  17.             wrapper.like(User::getUsername, name);
  18.         }
  19.         if (status != null) {
  20.             wrapper.eq(User::getStatus, status);
  21.         }
  22.         if (sortBy != null) {
  23.             if (isAsc) {
  24.                 wrapper.orderByAsc(sortBy);
  25.             } else {
  26.                 wrapper.orderByDesc(sortBy);
  27.             }
  28.         } else {
  29.             wrapper.orderByDesc(User::getUpdateTime);
  30.         }
  31.         Page<User> resultPage = userService.page(page, wrapper);
  32.         return PageDTO.of(resultPage);
  33.     }
  34. }
复制代码
同时,须要在PageQuery和PageDTO中界说方法,实现PageQuery对象与 MyBatis-Plus 中的Page对象转换,以及Page结果到PageDTO结果的转换:
  1. public class PageQuery {
  2.     public static Page of(PageQuery pageQuery) {
  3.         return new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
  4.     }
  5. }
  6. public class PageDTO<T> {
  7.     private long total;
  8.     private int pages;
  9.     private List<T> list;
  10.     public static <T> PageDTO<T> of(Page<T> page) {
  11.         PageDTO<T> pageDTO = new PageDTO<>();
  12.         pageDTO.total = page.getTotal();
  13.         pageDTO.pages = page.getPages();
  14.         pageDTO.list = page.getRecords();
  15.         return pageDTO;
  16.     }
  17. }
复制代码
六、总结

MyBatis-Plus 在 MyBatis 的基础上提供了丰富的功能和便捷的开辟体验。通过本教程,开辟者学习了从快速入门到焦点功能、扩展功能以及插件功能的利用。把握这些知识后,开辟者能够在项目中机动运用 MyBatis-Plus,高效地完成数据库操纵相关的开辟任务,进步项目开辟效率和质量。在实际应用中,可根据项目需求合理选择和配置 MyBatis-Plus 的各项功能,不绝优化代码和性能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4