目录

MyBatis-Plus笔记

MyBatis-Plus 通用BaseMapper使用介绍

详细见快速开始

  • 拥有 Java 开发环境以及相应 IDE
  • 熟悉 Spring Boot
  • 熟悉 Maven

现有一张 User 表,其表结构如下:

id name age email
1 Jone 18 test1@baomidou.com
2 Jack 20 test2@baomidou.com
3 Tom 28 test3@baomidou.com
4 Sandy 21 test4@baomidou.com
5 Billie 24 test5@baomidou.com

其对应的数据库 Schema 脚本如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

其对应的数据库 Data 脚本如下:

1
2
3
4
5
6
7
8
DELETE FROM user;

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'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

::: danger Question 如果从零开始用 MyBatis-Plus 来实现该表的增删改查我们需要做什么呢? :::

初始化工程

创建一个空的 Spring Boot 工程(工程将以 H2 作为默认数据库进行演示)

::: tip 可以使用 Spring Initializer 快速初始化一个 Spring Boot 工程 :::

添加依赖

引入 Spring Boot Starter 父工程:

1
2
3
4
5
6
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>spring-latest-version</version>
    <relativePath/>
</parent>

引入 spring-boot-starterspring-boot-starter-testmybatis-plus-boot-starterh2 依赖:

Latest Version: https://camo.githubusercontent.com/ee24dda3b035bffc9c281a31d013dcab59722b40d396818e19bf7cd76a756324/68747470733a2f2f696d672e736869656c64732e696f2f6d6176656e2d63656e7472616c2f762f636f6d2e62616f6d69646f752f6d7962617469732d706c75732e737667

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>Latest Version</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

配置

application.yml 配置文件中添加 H2 数据库的相关配置:

1
2
3
4
5
6
7
8
9
# DataSource Config
spring:
  datasource:
    driver-class-name: org.h2.Driver
    schema: classpath:db/schema-h2.sql
    data: classpath:db/data-h2.sql
    url: jdbc:h2:mem:test
    username: root
    password: test

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(QuickStartApplication.class, args);
    }

}

编码

编写实体类 User.java(此处使用了 Lombok 简化代码)

1
2
3
4
5
6
7
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

编写Mapper类 UserMapper.java

1
2
3
public interface UserMapper extends BaseMapper<User> {

}

开始使用

添加测试类,进行功能测试:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@SpringBootTest
public class SampleTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        Assert.assertEquals(5, userList.size());
        userList.forEach(System.out::println);
    }

}

::: tip UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件 :::

控制台输出:

1
2
3
4
5
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

::: tip 完整的代码示例请移步:Spring Boot 快速启动示例 | Spring MVC 快速启动示例 :::

小结

通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。

但 MyBatis-Plus 的强大远不止这些功能,想要详细了解 MyBatis-Plus 的强大功能,请继续学习

MyBatis-Plus 通用IService使用介绍

一、引言

MP除了通用的Mapper还有通用的Servcie层,这也减少了相对应的代码工作量,把通用的接口提取到公共。其实按照MP的这种思想,可以自己也实现一些通用的Controller。

由于官网文档没有IService的使用教程,快速开始仅仅有Mapper的教程,故写了本文

二、IService使用

Service

Service层需要继承IService,当然实现层也要继承对应的实现类。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * <p>
 * 用户 服务类
 * </p>
   *
 * @author IT贱男
 * @since 2019-06-14
   */
   public interface UserService extends IService<User> {
}

/**
 * <p>
 * 用户 服务实现类
 * </p>
   *
 * @author IT贱男
 * @since 2019-06-14
   */
   @Service
   public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

这里基本的增删改查就不一一演示了,演示几个特殊一点的方法。

getOne(),这个是方法返回结果不止一条则会抛出异常,如果想默认取第一条结果,可以给这方法传第二个参数为false。

1
2
3
4
5
  @Test
    public void getOne() {
        User one = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getAge, 31),false);
        System.out.println(one);
    }

saveOrUpdateBatch(),批量新增或者修改方法,判断ID是否存在,如果ID不存在执行新增,如果ID存在先执行查询语句,查询结果为空新增,否则修改。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
   @Test
    public void saveOrUpdateBatch() {
        User user1 = new User();
        user1.setName("兔子");
        user1.setAge(18);   
        User user2 = new User();
        user2.setId(1088250446457389060L);
        user2.setName("乌龟");
        user2.setAge(18);

        List<User> users = Arrays.asList(user1, user2);

        boolean b = userService.saveOrUpdateBatch(users);
        System.out.println(b);
}

接下来说一下基于lambda的相关操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 /**
     * lombda查询
     */
    @Test
    public void lambdaQuery(){
        List<User> list = userService.lambdaQuery().eq(User::getAge, 18).list();
        list.forEach(System.out::println);
    }

/**
 * lombda修改
 */
@Test
public void lambdaUpdate(){
    boolean update = userService.lambdaUpdate().eq(User::getAge, 18).set(User::getAge, 31).update();
    System.out.println(update);
}
 
/**
 * lombda删除
 */
@Test
public void lambdaRemoce(){
    boolean remove = userService.lambdaUpdate().eq(User::getAge, 18).remove();
    System.out.println(remove);
}

Maybatis-Plus lambdaQuery和mapper中EQ、NE、GT、LT、GE、LE的对时间的用法及详解

1.等于当前时间

1
taskFlowService.lambdaQuery().eq(TaskFlow::getCreateTime,DateUtil.now())

2.不等于当前时间

1
taskFlowService.lambdaQuery().ne(TaskFlow::getCreateTime,DateUtil.now());

3.大于当前时间

1
taskFlowService.lambdaQuery().gt(TaskFlow::getCreateTime,DateUtil.now());

4.小于当前时间

1
taskFlowService.lambdaQuery().lt(TaskFlow::getCreateTime,DateUtil.now());

5.大于等于当前时间

1
taskFlowService.lambdaQuery().ge(TaskFlow::getCreateTime,DateUtil.now());

6.小于等于当前时间

1
taskFlowService.lambdaQuery().le(TaskFlow::getCreateTime,DateUtil.now());

7.2个时间段是否相交

1
2
3
if((!start1.after(end2))&&(!end1.before(start2))){
        System.out.println("时间重叠");
    }

MyBatis-Plus 更新操作示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@Component
public class UserMapperUpdateTest extends MybatisPlusSamplesChapter1ApplicationTests {
    @Resource
    private UserMapper userMapper;

    @Test
    public void updateById() {
        User user = new User();
        user.setId(1087982257332887553L);
        user.setEmail("gblfy@163.com");
        user.setAge(22);

        int rows = userMapper.updateById(user);
        System.out.println("影响记录数:" + rows);
    }
    //UPDATE user SET age=?, email=? WHERE id=?

    /**
     * 根据 whereEntity 条件,更新记录
     *
     * @param entity        实体对象 (set 条件值,可以为 null)
     * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
     */
    @Test
    public void updateByWrapper() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "李艺伟")
                .eq("age", 28);

        User user = new User();
        user.setEmail("gblfy2@sino.com");
        user.setAge(22);

        int rows = userMapper.update(user, updateWrapper);
        System.out.println("影响记录数:" + rows);
    }
    //UPDATE user SET age=?, email=? WHERE name = ? AND age = ?

    /**
     * 当表中字段很多,只更新少量字段的值(建议使用)
     */
    @Test
    public void updateByWrapper2() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "李艺伟")
                .eq("age", 28)
                .set("age", 30);

        int rows = userMapper.update(null, updateWrapper);
        System.out.println("影响记录数:" + rows);
    //UPDATE user SET age=?, email=? WHERE name = ? AND age = ?
    }

    @Test
    public void updateByWrapperLambda() {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = Wrappers.<User>lambdaUpdate();
        lambdaUpdateWrapper.eq(User::getName, "李艺伟")
                .eq(User::getAge, 28)
                .set(User::getAge, 30);

        int rows = userMapper.update(null, lambdaUpdateWrapper);
        System.out.println("影响记录数:" + rows);
    }

    @Test
    public void updateByWrapperLambdaChain() {
        boolean sign = new LambdaUpdateChainWrapper<User>(userMapper)
                .eq(User::getName, "李艺伟")
                .eq(User::getAge, 22)
                .set(User::getAge, 30).update();

        System.out.println(sign);
    }
    //UPDATE user SET age=? WHERE name = ? AND age = ?

MyBatis-Plus 分页查询示例

IPage封装了各种分页的信息,包括不限于总页数,当前页数,总个数,是否有上一页或下一页等

1
2
3
4
5
@GetMapping("/user/allpage")
public IPage<PrimaryUser> getAllIP() {
    IPage<PrimaryUser> primaryUserPage = primaryUserMapper.selectPage(new Page<>(1,2),null);
    return primaryUserPage;
}

MyBatis-Plus 模糊查询及QueryWrapper<>常用条件方法介绍

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
通用条件:】
比较大小 ( =, <>, >, >=, <, <= )
    eq(R column, Object val); // 等价于 =,例: eq("name", "老王") ---> name = '老王'
    ne(R column, Object val); // 等价于 <>,例: ne("name", "老王") ---> name <> '老王'
    gt(R column, Object val); // 等价于 >,例: gt("name", "老王") ---> name > '老王'
    ge(R column, Object val); // 等价于 >=,例: ge("name", "老王") ---> name >= '老王'
    lt(R column, Object val); // 等价于 <,例: lt("name", "老王") ---> name < '老王'
    le(R column, Object val); // 等价于 <=,例: le("name", "老王") ---> name <= '老王'

范围:(betweennot betweeninnot in)】
   between(R column, Object val1, Object val2); // 等价于 between a and b, 例: 			between("age", 18, 30) ---> age between 18 and 30
   notBetween(R column, Object val1, Object val2); // 等价于 not between a and b, 例: 	notBetween("age", 18, 30) ---> age not between 18 and 30
   in(R column, Object... values); // 等价于 字段 IN (v0, v1, ...),例: in("age",{1,2,3}) ---> age in (1,2,3)
   notIn(R column, Object... values); // 等价于 字段 NOT IN (v0, v1, ...), 例: notIn("age",{1,2,3}) ---> age not in (1,2,3)
   inSql(R column, Object... values); // 等价于 字段 IN (sql 语句), 例: inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
   notInSql(R column, Object... values); // 等价于 字段 NOT IN (sql 语句)

模糊匹配:(like)】
    like(R column, Object val); // 等价于 LIKE '%值%',例: like("name", "王") ---> name like '%王%'
    notLike(R column, Object val); // 等价于 NOT LIKE '%值%',例: notLike("name", "王") ---> name not like '%王%'
    likeLeft(R column, Object val); // 等价于 LIKE '%值',例: likeLeft("name", "王") ---> name like '%王'
    likeRight(R column, Object val); // 等价于 LIKE '值%',例: likeRight("name", "王") ---> name like '王%'

空值比较:(isNullisNotNull)】
    isNull(R column); // 等价于 IS NULL,例: isNull("name") ---> name is null
    isNotNull(R column); // 等价于 IS NOT NULL,例: isNotNull("name") ---> name is not null

分组排序:(grouphavingorder)】
    groupBy(R... columns); // 等价于 GROUP BY 字段, ..., 例: groupBy("id", "name") ---> group by id,name
    orderByAsc(R... columns); // 等价于 ORDER BY 字段, ... ASC, 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
    orderByDesc(R... columns); // 等价于 ORDER BY 字段, ... DESC, 例: orderByDesc("id", "name") ---> order by id DESC,name DESC
    having(String sqlHaving, Object... params); // 等价于 HAVING ( sql语句 ), 例: having("sum(age) > {0}", 11) ---> having sum(age) > 11

拼接嵌套 sql:(orandnestedapply)】
   or(); // 等价于 a or b, 例:eq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王'
   or(Consumer<Param> consumer); // 等价于 or(a or/and b),or 嵌套。例: or(i -> i.eq("name", "李白").ne("status", "活着")) ---> or (name = '李白' and status <> '活着')
   and(Consumer<Param> consumer); // 等价于 and(a or/and b),and 嵌套。例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')
   nested(Consumer<Param> consumer); // 等价于 (a or/and b),普通嵌套。例: nested(i -> i.eq("name", "李白").ne("status", "活着")) ---> (name = '李白' and status <> '活着')
   apply(String applySql, Object... params); // 拼接sql(若不使用 params 参数,可能存在 sql 注入),例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
   last(String lastSql); // 无视优化规则直接拼接到 sql 的最后,可能存若在 sql 注入。
   exists(String existsSql); // 拼接 exists 语句。例: exists("select id from table where age = 1") ---> exists (select id from table where age = 1)

QueryWrapper 条件:】
    select(String... sqlSelect); // 用于定义需要返回的字段。例: select("id", "name", "age") ---> select id, name, age
    select(Predicate<TableFieldInfo> predicate); // Lambda 表达式,过滤需要的字段。
    lambda(); // 返回一个 LambdaQueryWrapper

UpdateWrapper 条件:】
    set(String column, Object val); // 用于设置 set 字段值。例: set("name", null) ---> set name = null
    etSql(String sql); // 用于设置 set 字段值。例: setSql("name = '老李头'") ---> set name = '老李头'
    lambda(); // 返回一个 LambdaUpdateWrapper

我们直接创建测试类进行展示

1
 QueryWrapper<User> wrapper = new QueryWrapper<>();

QueryWrapper<>中,有很多已经编译好的方法,我们可以直接进行调用,

./1.png

./2.png

1
2
3
4
5
6
7
8
@Test
void test4(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.likeRight("name","K");
    // .likeRight("email",4); 右查询  左%e%右
    List<Map<String,Object>>maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}

在test4的方法中,使用likeRight进行查询带有K的数据

或者使用自己注入的sql语句,

1
2
3
4
5
6
7
8
@Test
void test5(){
    //模糊查询
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id","select id from user where id);
                  List<Object>objects = userMapper.selectObjs(wrapper);
                  objects.forEach(System.out::println);
}

当我们需要在Controller中使用方法时,需要把 QueryWrapper wrapper = new QueryWrapper<>();语句写入到Service层中

./3.png

Service

./4.png

这样我们在Controller中可以避免直接调用mapper层