1、MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

2、特性:

  • 无侵入:在mybatis基础上只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

 扫描实体类,通过反射,分析出表名以及字段,然后自动生成CRUD的SQL语句,最后注入到mybatis容器中

3、Lambda表达式

Lambda 表达式是 Java 8 中引入的一种新特性,它可以用更简洁的语法来表示匿名函数。Lambda 表达式通常由三个部分组成:

  1. 形参列表:使用小括号 () 括起来,多个参数之间使用逗号分隔。

  2. 箭头符号:用于连接形参列表和 Lambda 表达式的主体部分,可以是 -> 或者 ::。

  3. Lambda 表达式的主体:可以是一个表达式,也可以是一个代码块。如果是一个表达式,则不需要使用 return 关键字返回值;如果是一个代码块,则需要使用大括号 {} 括起来,并使用 return 关键字返回值。

Lambda 表达式的语法如下:

(parameters) -> expression

或者

(parameters) -> { statements; }

其中 parameters 是形参列表,expression 是单个表达式,statements 是一组语句。

Lambda 表达式还可以使用预定义的函数式接口,例如 Runnable、Consumer、Predicate 等,以简化代码的编写。以下是一个使用 Predicate 接口的示例:

List<String> list = Arrays.asList("Java", "Python", "C++", "JavaScript");
Predicate<String> predicate = s -> s.startsWith("J");
list.stream().filter(predicate).forEach(System.out::println); // 输出 Java JavaScript

以上代码中,我们首先创建了一个 Predicate 对象,用于过滤以字母 J 开头的字符串。然后使用 stream() 方法将 List 转化为流,再使用 filter() 方法对流进行过滤,最后使用 forEach() 方法遍历输出结果。

 

4、条件构造器(Wrapper

  • Wrapper:条件构造器抽象类,最顶端的父类
    • AbstractWrapper:查询条件封装抽象类,生成 SQL 的 where 条件
      • QueryWrapper:用于对象封装
      • UpdateWrapper:用于条件封装
    • AbstractLambdaWrapper:Lambda 语法使用 Wrapper
      • LambdaQueryWrapper:用于对象封装,使用 Lambda 语法
      • LambdaUpdateWrapper:用于条件封装,使用 Lambda 语法

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootTest
@MapperScan("com.wwj.mybatisplusdemo.mapper")
class MybatisplusDemoApplicationTests {
 
    @Autowired
    private EmployeeMapper employeeMapper;
 
    @Test
    void contextLoads() {
        // 查询名字中包含'j',年龄大于20岁,邮箱不为空的员工信息
        QueryWrapper<Employee> wrapper = new QueryWrapper<>();
        wrapper.like("last_name", "j");
        wrapper.gt("age", 20);
        wrapper.isNotNull("email");
        List<Employee> list = employeeMapper.selectList(wrapper);
        list.forEach(System.out::println);
    }
}

  

1
2
3
4
5
6
7
8
9
10
@Test
void contextLoads() {
    // 查询名字中包含'j',年龄大于20岁,邮箱不为空的员工信息
    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<Employee>()
        .like(Employee::getLastName,"j")
        .gt(Employee::getAge,20)
        .isNotNull(Employee::getEmail);
    List<Employee> list = employeeMapper.selectList(wrapper);
    list.forEach(System.out::println);
}

  UpdateWrapper 与 QueryWrapper 不同,它的作用是封装更新内容的,比如:

1
2
3
4
5
6
7
8
9
@Test
void contextLoads() {
    UpdateWrapper<Employee> wrapper = new UpdateWrapper<Employee>()
        .set("age", 50)
        .set("email", "emp@163.com")
        .like("last_name", "j")
        .gt("age", 20);
    employeeMapper.update(null, wrapper);
}

  

5、分页插件

对于分页功能,MyBatisPlus 提供了分页插件,只需要进行简单的配置即可实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class MyBatisConfig {
 
    /**
     * 注册分页插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

  接下来我们就可以使用分页插件提供的功能了:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
void contextLoads() {
    Page<Employee> page = new Page<>(1,2);
    employeeService.page(page, null);
    List<Employee> employeeList = page.getRecords();
    employeeList.forEach(System.out::println);
    System.out.println("获取总条数:" + page.getTotal());
    System.out.println("获取当前页码:" + page.getCurrent());
    System.out.println("获取总页码:" + page.getPages());
    System.out.println("获取每页显示的数据条数:" + page.getSize());
    System.out.println("是否有上一页:" + page.hasPrevious());
    System.out.println("是否有下一页:" + page.hasNext());
}

  倘若在分页过程中需要限定一些条件,我们就需要构建 QueryWrapper 来实现:

1
2
3
4
5
6
7
8
9
@Test
void contextLoads() {
    Page<Employee> page = new Page<>(1, 2);
    employeeService.page(page, new QueryWrapper<Employee>()
                         .between("age", 20, 50)
                         .eq("gender", 1));
    List<Employee> employeeList = page.getRecords();
    employeeList.forEach(System.out::println);
}