MyBatis-Plus入门和使用实践

文章目录

MyBatis-Plus入门和使用实践

一、前言

  1. 环境说明
  • 操作系统:Windows 10 专业版
  • Mybatis-Plus 版本:3.4.2
  • JDK 版本:1.8
  • 开发工具:IntelliJ IDEA 2020.2.2
  1. 简介
  • MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

    特性:

  1. 无侵入、消耗小、强大的 CRUD 操作
  2. 支持 Lambda 形式调用,支持多种数据库
  3. 支持主键自动生成,支持 ActiveRecord 模式
  4. 支持自定义全局通用操作,支持关键词自动转义
  5. 内置代码生成器,内置分页插件,内置性能分析插件
  6. 内置全局拦截插件,内置 SQL 注入剥离器

MyBatis-Plus 官网:https://mp.baomidou.com/

MyBatis 官网:https://mybatis.org/mybatis-3/zh/index.html

Spring Data JPA:https://spring.io/projects/spring-data-jpa

Active Record 模式-百度百科:https://baike.baidu.com/item/Active%20Record/3106858?fr=aladdin

二、正文

1.创建项目

1)引入依赖

  • pom.xml 引入依赖 mybatis-plus、lombok、spring-boot
<!-- spring-boot-starter 父工程 -->
<parent>
  <artifactId>spring-boot-starter-parent</artifactId>
  <groupId>org.springframework.boot</groupId>
  <version>2.1.3.RELEASE</version>
</parent>

<dependencies>
  <!-- spring-boot 启动器 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <!-- spring-boot 测试启动器 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <!-- lombok -->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency>
  <!-- mybatis-plus spring-boot 启动器 -->
  <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
  </dependency>
  <!-- mybatis-plus -->
  <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.4.2</version>
  </dependency>
  <!-- mysql 驱动 -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>
  <!-- junit -->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>
</dependencies>

2)SpringBoot配置

  • resources 文件夹创建 application.yml
# mysql 连接配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp-db?useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root2020
# 输入日志,查看 sql 语句
logging:
  level:
    root: warn
    org.example.dao: trace
  pattern:
    console: '%p%m%n'
  • App.java 启动 spring-boot
package org.example;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * spring-boot 启动入口
 *
 */
@SpringBootApplication
@MapperScan({"org.example.dao"})
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }
}

3)测试数据

  • sql 脚本
#创建用户表
CREATE TABLE user (
    id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键',
    name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
    age INT(11) DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
    manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
    create_time DATETIME DEFAULT NULL COMMENT '创建时间',
    CONSTRAINT manager_fk FOREIGN KEY (manager_id)
        REFERENCES user (id)
)  ENGINE=INNODB CHARSET=UTF8;

#初始化数据:
INSERT INTO user (id, name, age, email, manager_id, create_time)
VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
		, '2019-01-11 14:20:20'),
	(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553
		, '2019-02-05 11:12:22'),
	(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385
		, '2019-02-14 08:31:16'),
	(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
		, '2019-01-14 09:15:15'),
	(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385
		, '2019-01-14 09:48:16');
  • 创建 entity/User.java
package org.example.entity;

import lombok.Data;

import java.time.LocalDateTime;

/***
 * 员工实体类
 * */
@Data
public class User {
    // 员工 ID
    private Long id;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 邮箱
    private String email;
    // 上级领导 ID
    private Long managerId;
    // 创建时间
    private LocalDateTime createTime;
}
  • 创建 dao/UserMapper.java (接口)
package org.example.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.example.entity.User;

public interface UserMapper extends BaseMapper<User> {

}

4)测试例子

  • 测试类:AppTest.java
package org.example;

import org.example.dao.UserMapper;
import org.example.entity.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class AppTest 
{
    @Autowired
    private UserMapper userMapper;

    /**
     * 查询列表
     * */
    @Test
    public void select()
    {
        List<User> users = userMapper.selectList(null);
        // 判断预期值与实际值是否相同
        // Assert.assertEquals(5, users.size());
        // 循环输出
        users.forEach(System.err::println);
    }
}

2.常用注解

注解 说明
@TableName(“数据库表名”) 指定实体类对应的数据库表名
@TableId 指定属性作为主键,mp 默认 id 为主键
@TableId(type = IdType.ASSIGN_UUID) 指定属性作为主键,并指定主键策略
@TableField(“数据库表字段名”) 指定属性对应的数据库表字段名
@TableField(exist=false) 实体属性排除映射;将属性标记为非数据库表字段
@TableField(condition = SqlCondition.LIKE) 当实体对象作为条件构造器的查询条件时,属性可进行 like 查询,而非默认的等值(SqlCondition 中还有其它常量可选)

3.查询

1)普通条件查询

  • ID 查询
@Test
public void selectById()
{
    // 根据 ID 进行查询
    User user = userMapper.selectById(1087982257332887553L);
    System.err.println(user);
}
  • 批量 ID 查询
@Test
public void selectBatchIds()
{
    List<Long> ids = Arrays.asList(1087982257332887553L, 1088248166370832385L);
    // 根据 ID 列表进行查询
    List<User> users = userMapper.selectBatchIds(ids);
    users.forEach(System.err::println);
}
  • 根据 map 查询
@Test
public void selectByMap()
{
    Map map = new HashMap();
    map.put("name", "大boss"); // 数据库表字段名
    map.put("age", 40);
    // sql:where name = '大boss' and age =40
    // 根据 Map {name : value} 进行查询
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.err::println);
}

2)条件构造器查询

  • 名字中包含’雨’,并且年龄小于 40

where name like ‘%雨%’ and age < 40

@Test
public void selectByWrapper()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 名字中包含’雨’,年龄大于等于 20,且小于等于 40,且邮箱不为空

where name like ‘%雨%’ and age between 20 and 40 and email is not null

@Test
public void selectByWrapper2()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like("name", "雨")
            .between("age", 20, 40)
            .isNotNull("email"); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 名字姓’张’,或者年龄大于等于 30,按年龄降序排列,年龄相同的按id升序排列

where name like ‘张%’ or age >= 30 order by age desc,id asc

@Test
public void selectByWrapper3()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like("name", "张%")
            .or()
            .ge("age", 30)
            .orderByDesc("age")
            .orderByAsc("id"); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 创建日期是’2019-02-14’,且上级领导姓’王’

where date_format(create_time, ‘%Y-%m-%d’)

and manager_id in (select id from user where name like ‘王%’)

@Test
public void selectByWrapper4()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}"
                        , "2019-02-14") // {0} 参数序号
                .inSql("manager_id"
                        , "select id from user where name like '王%'");
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 姓’王’,且(年龄小于 40 或邮箱不为空)

where name like ‘王%’ and (age<40 or email is not null)

@Test
public void selectByWrapper5()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.likeRight("name", "王")
            .and( wq->wq.lt("age", 40)
                    .or()
                    .isNotNull("email")
            ); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 姓’王’,或者(年龄小于 40 且大于 20 且邮箱不为空)

where name like ‘王%’ or (age<40 and age>20 and email is not null)

@Test
public void selectByWrapper6()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.likeRight("name", "王")
            .or( wq->wq.lt("age", 40)
                    .gt("age", 20)
                    .isNotNull("email")
            ); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • (年龄小于 40 或邮箱不为空) 且姓’王’

where (age<40 or email is not null) and name like ‘王%’

@Test
public void selectByWrapper7()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.nested( wq->wq.lt("age", 40).or().isNotNull("email") )
            .likeRight("name", "王"); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 年龄包含 30、31、34

where age in (30, 31, 34)

@Test
public void selectByWrapper8()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.in("age", Arrays.asList(30, 31, 32)); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 仅获取一条数据

limit 1

@Test
public void selectByWrapper9()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.in("age", Arrays.asList(30, 31, 32))
            .last("limit 1"); // last 方法存在 sql 注入的风险
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}

3)Lambda条件构造器

  • 使用 lambda 表达式,可以避免数据库表字段名误写
@Test
public void selectByWrapperLambda()
{
    // LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper();
    // LambdaQueryWrapper<User> lambdaQueryWrapper = new QueryWrapper<User>().lambda();
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    
    lambdaQueryWrapper.like(User::getName, "雨").lt(User::getAge, 40);
    
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(lambdaQueryWrapper);
    users.forEach(System.err::println);
}
  • 链式编程
@Test
public void selectByWrapperChain()
{
    List<User> users = new LambdaQueryChainWrapper<User>( userMapper )
            .like(User::getName, "雨")
            .lt(User::getAge, 40)
            .list();
    users.forEach(System.err::println);
}

4)常用查询

排除查询字段

  • 名字包含’雨’,且年龄小于 40 ( 只查询 id 和 name 字段 )

select id,name from user where name like ‘雨%’ and age < 40

@Test
public void selectByWrapper10()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.select("id", "name")
            .like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}
  • 名字包含’雨’,且年龄小于 40 ( 查询排除 create_time 和 manager_id )

select id,name,age,email from user where name like ‘雨%’ and age < 40

@Test
public void selectByWrapper11()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.select(User.class, u->!u.getColumn().equals("create_time")
                                        &&!u.getColumn().equals("manager_id"))
            .like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}

是否使用某个条件

  • 如果 name 或 email 为空,则不使用该条件进行查询
@Test
public void selectByWrapper12()
{
    String name = "雨";
    String email = "";
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like(StringUtils.isNotBlank(name), "name", name)
            .like(StringUtils.isNotBlank(email), "email", email); // 数据库表字段名
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}

实体对象作为条件

  • 名字是’李艺伟’,且年龄是28

where name=‘李艺伟’ and age=28

@Test
public void selectByWrapper13()
{
    User user = new User();
    user.setName("李艺伟");
    user.setAge(28);
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query(user);
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}

注意: 默认为等值查询,如果需要模糊查询,需要在实体类的属性中添加注解 @TableField(condition = SqlCondition.LIKE)

例如:

@TableField(condition = SqlCondition.LIKE)
private String name;

条件全匹配

  • 1.查询条件全匹配,包括 null 也会作为查询条件
  • 2.设置 false 时;如果参数为 null,则参数会排除,不作为查询条件
  • 3.通过函数,可排除某些字段作为查询条件
@Test
public void selectByWrapperAllEq()
{
    Map map =new HashMap();
    map.put("name", "大boss");
    map.put("email", null);
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    // 1.全匹配
    // queryWrapper.allEq(map);
    // 2.设置为 false 时,如果参数为 null,则参数会排除,不作为查询条件
    // queryWrapper.allEq(map, false);
    // 3.通过函数,排除某些字段作为查询条件;例如:排除 name 字段作为查询条件
    queryWrapper.allEq((k,v)->!k.equals("name"), map);
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.err::println);
}

Map结果(统计)

  • 返回 Map 对象,可避免实体对象因为排除查询字段后,大多数字段为空的情况
@Test
public void selectByWrapperMaps()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.select("id", "name")
            .like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    List<Map<String, Object>> users = userMapper.selectMaps(queryWrapper);
    users.forEach(System.err::println);
}
  • 按上级领导分组,查询分组的评价年龄,最大年龄,最小年龄,并且只取年龄总和小于500的分组

SELECT AVG(age) avg_age, MIN(age) min_age, MAX(age) max_age
FROM user
GROUP BY manager_id
HAVING SUM(age) < 500

@Test
public void selectByWrapperMaps2()
{
    // 创建条件构造器
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.select("AVG(age) avg_age", "MIN(age) min_age", "MAX(age) max_age")
            .groupBy("manager_id")
            .having("SUM(age) < {0}", 500); // 数据库表字段名
    // 根据条件构造器进行查询
    List<Map<String, Object>> users = userMapper.selectMaps(queryWrapper);
    users.forEach(System.err::println);
}

其它查询

  • 仅获取第一列数据,如下查询,仅输出 id 字段的数据
@Test
public void selectByWrapperObjs()
{
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.select("id", "name")
            .like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    List<Object> users = userMapper.selectObjs(queryWrapper);
    users.forEach(System.err::println);
}
  • 统计记录数

注意:不能指定字段

@Test
public void selectByWrapperCount()
{
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like("name", "雨")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    Integer count = userMapper.selectCount(queryWrapper);
    System.out.println("总记录数:"+count);
}
  • 查询一条数据

注意:查询结果有多条时,会报错

@Test
public void selectByWrapperOne()
{
    QueryWrapper<User> queryWrapper = Wrappers.query();
    queryWrapper.like("name", "张雨琪")
            .lt("age", 40); // 数据库表字段名
    // 根据条件构造器进行查询
    User user = userMapper.selectOne(queryWrapper);
    System.out.println(user);
}

5)自定义SQL

接口类实现

  • dao/UserMapper.java
  • 条件构造器作为sql参数
package org.example.dao;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.entity.User;

import java.util.List;

public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据条件构造器进行查询
     * */
    @Select("select * from user ${ew.customSqlSegment}")
    public List<User> selectByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

  • 测试类:AppTest.java
@Test
public void selectByWrapperSQL()
{
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    lambdaQueryWrapper.like(User::getName, "雨").lt(User::getAge, 40);
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectByWrapper(lambdaQueryWrapper);
    users.forEach(System.err::println);
}

XML实现

  • application.yml 配置 mybatis-plus 的 mapper 文件目录
# mybatis-plus
mybatis-plus:
  # mapper 目录
  mapper-locations: classpath*:mapper/*Mapper.xml
  • resources/mapper/UserMapper.xml (resources 资源目录下)
  • 条件构造器作为sql参数
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:命名空间,指定为接口的全类名
-->
<mapper namespace="org.example.dao.UserMapper">
    <!--接口方式:
      id:接口方法名 ,resultType:返回类型
    -->
    <select id="selectByWrapperXML" resultType="org.example.entity.User">
        select * from user ${ew.customSqlSegment}
    </select>
</mapper>
  • dao/UserMapper.java
package org.example.dao;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.entity.User;

import java.util.List;

public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据条件构造器进行查询,SQL 语句配置在 XML 文件中
     * */
    public List<User> selectByWrapperXML(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

  • 测试类:AppTest.java
@Test
public void selectByWrapperSQL2()
{
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    lambdaQueryWrapper.like(User::getName, "雨").lt(User::getAge, 40);
    // 根据条件构造器进行查询
    List<User> users = userMapper.selectByWrapperXML(lambdaQueryWrapper);
    users.forEach(System.err::println);
}

6)分页查询

mybatis 分页仅实现了逻辑分页,即将数据全部加载到内存,然后再分页。

Config配置

  • 创建 config/MybatisPlusConfig.java
package org.example.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,
     * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
     * 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}

BaseMapper分页查询

  • 测试类:AppTest.java
@Test
public void selectByWrapperPage()
{
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    lambdaQueryWrapper.gt(User::getAge, 20);
    // 分页查询
    // Page<User> page = new Page<>(1, 3);
    // IPage<User> iPage = userMapper.selectPage(page, lambdaQueryWrapper);
    // Map
    Page page = new Page<>(1, 3);
    IPage<Map<String, Object>> iPage = userMapper.selectMapsPage(page, lambdaQueryWrapper);
    // 输出结果
    System.err.println("当前页:"+iPage.getCurrent());
    System.err.println("总页数:"+iPage.getPages());
    System.err.println("总记录数:"+iPage.getTotal());
    iPage.getRecords().forEach(System.err::println);
}
  • 屏蔽总记录数的查询
Page<User> page = new Page<>(1, 3, false);

自定义SQL分页查询

  • dao/UserMapper.java
package org.example.dao;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.entity.User;

import java.util.List;

public interface UserMapper extends BaseMapper<User> {

    /**
     * 分页查询
     * */
    public IPage<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

  • resources/mapper/UserMapper.xml (resources 资源目录下)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:命名空间,指定为接口的全类名
-->
<mapper namespace="org.example.dao.UserMapper">
    <!--接口方式:
      id:接口方法名 ,resultType:返回类型
    -->
    <select id="selectUserPage" resultType="org.example.entity.User">
        select * from user ${ew.customSqlSegment}
    </select>
</mapper>
  • 测试类:AppTest.java
@Test
public void selectByWrapperPage2()
{
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    lambdaQueryWrapper.gt(User::getAge, 20);
    // 分页查询
    Page<User> page = new Page<>(1, 3);
    IPage<User> iPage = userMapper.selectUserPage(page, lambdaQueryWrapper);
    // 输出结果
    System.err.println("当前页:"+iPage.getCurrent());
    System.err.println("总页数:"+iPage.getPages());
    System.err.println("总记录数:"+iPage.getTotal());
    iPage.getRecords().forEach(System.err::println);
}

4.增删改

新增

  • 测试类:AppTest.java
@Test
public void insert()
{
    User user = new User();
    user.setName("李小龙");
    user.setAge(22);
    user.setEmail("lxl@163.com");
    user.setManagerId(1088248166370832385L);
    user.setCreateTime(LocalDateTime.now());
    // 插入数据
    int num = userMapper.insert(user);
    System.err.println("影响记录数据:"+num);
    System.err.println("主键:"+user.getId());
}

更新

  • 根据 ID 更新
@Test
public void updateById()
{
    User user = new User();
    user.setId(1094592041087729666L);
    user.setAge(31);
    // 更新数据
    int num = userMapper.updateById(user);
    System.err.println("影响记录数据:"+num);
}
  • 根据条件构造器更新
@Test
public void updateByWrapper()
{
    // 条件构造器
    UpdateWrapper updateWrapper = new UpdateWrapper();
    updateWrapper.eq("name", "刘红雨");
    // 更新实体对象
    User user = new User();
    user.setAge(34);
    // 更新数据
    int num = userMapper.update(user,updateWrapper);
    System.err.println("影响记录数据:"+num);
}
  • 条件构造器中 set 方法,更新少量字段时使用
@Test
public void updateByWrapper2()
{
    // 条件构造器
    /*UpdateWrapper<User> updateWrapper = new UpdateWrapper();
    updateWrapper.eq("name", "刘红雨").set("age", 30);*/
    // Lambda 条件构造器
    LambdaUpdateWrapper<User> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
    lambdaUpdateWrapper.eq(User::getName, "刘红雨").set(User::getAge, 30); // set 方法设置修改的值
    // 更新数据
    int num = userMapper.update(null,lambdaUpdateWrapper);
    System.err.println("影响记录数据:"+num);

    // 链式编程
    boolean isUpdate = new LambdaUpdateChainWrapper<User>(userMapper)
            .eq(User::getName, "刘红雨")
            .set(User::getAge, 30)
            .update();
    System.err.println("更新成功:"+isUpdate);
}

删除

  • 根据 ID 删除
@Test
public void deleteById()
{
    Long userid = 1359388531205722114L;
    // 删除数据
    int num = userMapper.deleteById(userid);
    System.err.println("影响记录数据:"+num);
}
  • 其它删除方法
@Test
public void deleteByMap()
{
    Map<String, Object> map =new HashMap<>();
    map.put("name", "刘红雨");
    map.put("age", 30);
    // 删除数据
    int num = userMapper.deleteByMap(map);
    System.err.println("影响记录数据:"+num);
}

@Test
public void deleteByBatchId()
{
    List<Long> ids = Arrays.asList(123123123123L, 1233435234534L);
    // 删除数据
    int num = userMapper.deleteBatchIds(ids);
    System.err.println("影响记录数据:"+num);
}
  • 条件构造器删除
@Test
public void deleteByBWrapper()
{
    LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
    lambdaQueryWrapper.eq(User::getId, 12312312312312L);
    // 删除数据
    int num = userMapper.delete(lambdaQueryWrapper);
    System.err.println("影响记录数据:"+num);
}

5. AR模式

百度百科:[https://baike.baidu.com/item/Active%20Record/3106858?fr=aladdin](https://baike.baidu.com/item/Active Record/3106858?fr=aladdin)

  • Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。

具体操作

  1. 实体对象继承 com.baomidou.mybatisplus.extension.activerecord.Model (当前为 User)
  2. 编写好继承了 com.baomidou.mybatisplus.core.mapper.BaseMapperMapper (当前为 UserMapper)
  • entity/UserMapper.java
package org.example.entity;

import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;

import java.time.LocalDateTime;

/***
 * 员工实体类
 * */
@Data
public class User extends Model {
    // 用户 ID
    private Long id;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 邮箱
    private String email;
    // 上级领导 ID
    private Long managerId;
    // 创建时间
    private LocalDateTime createTime;
}
  • 测试类:ARTest.java
@Test
public void arSelect()
{
    User user = new User();
    // 查询数据
    List<User> users = user.selectAll();
    // 循环输出
    users.forEach(System.err::println);
}

@Test
public void arInsert()
{
    User user = new User();
    user.setName("路飞");
    user.setAge(25);
    user.setEmail("lf@163.com");
    user.setManagerId(1088248166370832385L);
    user.setCreateTime(LocalDateTime.now());
    // 新增数据
    boolean isInsert = user.insert();
    System.out.println("新增成功:"+isInsert);
}

@Test
public void arUpdate()
{
    User user = new User();
    user.setId(1359800186100056065L);
    user.setName("路飞飞");
    // 修改数据
    boolean isUpdate = user.updateById();
    System.out.println("更新成功:"+isUpdate);
}

@Test
public void arDelete()
{
    User user = new User();
    user.setId(1359800186100056065L);
    // 删除数据
    boolean isDelete = user.deleteById();
    System.out.println("删除成功:"+isDelete);
}

6.主键策略

  • 默认是基于雪花算法的主键策略
  • com.baomidou.mybatisplus.annotation.IdType.java
IdType 说明
AUTO(0) 数据库 ID 自增
NONE(1) 该类型为未设置主键类型 (注解里等于跟随全局,全局里约等于 INPUT)
INPUT(2) 用户输入 ID;
ASSIGN_ID(3) 分配ID (主键类型为number或string);默认 雪花算法
ASSIGN_UUID(4) 分配UUID (主键类型为 string)

全局策略配置

  • resources/application.yml
# mybatis-plus
mybatis-plus:
  # 全局主键配置
  global-config:
    db-config:
      id-type: assign_id

7.MP配置

MP配置官网文档:https://mp.baomidou.com/config/

  • 基本配置、全局配置、数据库配置

8.通用Service

  • Service 接口继承 com.baomidou.mybatisplus.extension.service.IService
  • Service 实现继承 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
  • 具体操作,参考 dao 的操作
上一篇:springboot + mybatis plus强大的条件构造器queryWrapper、updateWrapper


下一篇:搜索输入框建议提示(自动完成)功能实现