快速上手Mybatis Plus并速通MybatisPlus所有知识点

目录

一、简介

1.1 概况

1.2 特性

二、快速入门

1.建表

2.引依赖

3.application.ymal文件

4.定义mapper继承BaseMapper

5.总结

三、Mybatis Plus的使用

1.常见注解

1.1 @TableName

1.2 @TableId

1.3 @TableField

2.常见配置

3.BaseMapper的基础CRUD方法

4.Wrapper的使用(条件构造器)

4.1Wrapper的方法集

4.2QueryWapper的使用

4.3UpdateWrapper的使用

4.4LambdaQueryWrapper

5.Mapper分页查询

6.MyBatis Plus的Service查询


一、简介

1.1 概况

大家在日常开发中应该能发现,单表的CRUD功能代码重复度很高,也没有什么难度。而这部分代码量往往比较大,开发起来比较费时。

因此,目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是MybatisPlus.

1.2 特性

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

这里比较重要的几点就是,MybatisPlus不会对现有项目造成影响,也就是说你原有的项目使用的是Mybatis,再导入mybatisPlus之后也是可以继续运行的。

我们平时使用MybatisPlus的场景大多数是对单表的CRUD。

二、快速入门

1.建表

DROP TABLE IF EXISTS user;

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `sex` char(1) DEFAULT NULL COMMENT '性别 0:男 1:女',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `birthday` date DEFAULT NULL COMMENT '生日',
  PRIMARY KEY (`id`)
);


INSERT INTO `user` VALUES (1, 'Jone', '1', 27, '2001-10-04');
INSERT INTO `user` VALUES (2, 'Jack', '0', 20, '1999-10-04');
INSERT INTO `user` VALUES (3, 'Tom', '1', 28, '1996-08-12');
INSERT INTO `user` VALUES (4, 'Sandy', '1', 21, '2001-10-04');
INSERT INTO `user` VALUES (5, 'Billie', '0', 24, '1992-09-07');
INSERT INTO `user` VALUES (6, 'Jackson', '0', 18, '1996-08-12');
INSERT INTO `user` VALUES (7, 'Hardy', '1', 25, '1992-09-07');
INSERT INTO `user` VALUES (8, 'Rose', '1', 21, '1992-09-07');
INSERT INTO `user` VALUES (9, 'June', '0', 28, '1992-09-07');
INSERT INTO `user` VALUES (10, 'Aidan', '0', 17, '2001-10-04');

2.引依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

3.application.ymal文件

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2b8
    username: root
    password: admin
#配置日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.定义mapper继承BaseMapper

5.总结

三、Mybatis Plus的使用

1.常见注解

在刚刚的入门案例中,我们仅仅引入了依赖,继承了BaseMapper就能使用MybatisPlus,非常简单。但是问题来了: MybatisPlus如何知道我们要查询的是哪张表?表中有哪些字段呢?

大家回忆一下,UserMapper在继承BaseMapper的时候指定了一个泛型:

泛型中的User就是与数据库对应的PO.

MybatisPlus就是根据PO实体的信息来推断出表的信息,从而生成SQL的。默认情况下:

  • MybatisPlus会把PO实体的类名驼峰转下划线作为表名

  • MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型

  • MybatisPlus会把名为id的字段作为主键

但很多情况下,默认的实现与实际场景不符,因此MybatisPlus提供了一些注解便于我们声明表信息。

那万一你的表名、字段名、主键名都和数据库中的表、字段、主键都不一样,那Mybatis Plus怎么映射过去呢?(虽然说我们开发中一般不会故意出现这种情况,因为不规范,但有时候就是无法避免)

这时候就要使用MybatisPlus提供给我们的注释了

1.1 @TableName

  • 描述:表名注解,标识实体类对应的表

  • 使用位置:实体类

@TableName("user")
public class User {
    private Long id;
    private String name;
}

 该注解还有其他的属性配置,如下表:

value

String

""

表名

schema

String

""

schema

keepGlobalPrefix

boolean

false

是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)

resultMap

String

""

xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)

autoResultMap

boolean

false

是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)

excludeProperty

String[]

{}

需要排除的属性名 @since 3.3.1

1.2 @TableId

  • 描述:主键注解,标识实体类中的主键字段

  • 使用位置:实体类的主键字段

@TableName("user")
public class User {
    @TableId
    private Long id;
    private String name;
}

TableId注解支持两个属性:

属性

类型

必须指定

默认值

描述

value

String

""

表名

type

Enum

IdType.NONE

指定主键类型

IdType支持的类型有:

描述

AUTO

数据库 ID 自增

NONE

无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)

INPUT

insert 前自行 set 主键值

ASSIGN_ID

分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

ASSIGN_UUID

分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)

ID_WORKER

分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)

UUID

32 位 UUID 字符串(please use ASSIGN_UUID)

ID_WORKER_STR

分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

这里比较常见的有三种:

  • AUTO:利用数据库的id自增长

  • INPUT:手动生成id

  • ASSIGN_ID:雪花算法生成Long类型的全局唯一id,这是默认的ID策略

1.3 @TableField

说明:普通字段注解

@TableName("user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    @TableField("isMarried")
    private Boolean isMarried;
    @TableField("concat")
    private String concat;
}

一般情况下我们并不需要给字段添加@TableField注解,一些特殊情况除外:

  • 成员变量名与数据库字段名不一致

  • 成员变量是以isXXX命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符。

  • 成员变量名与数据库一致,但是与数据库的关键字冲突。使用@TableField注解给字段名添加转义字符:``

支持的其它属性如下:

属性

类型

必填

默认值

描述

value

String

""

数据库字段名

exist

boolean

true

是否为数据库表字段

condition

String

""

字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)

update

String

""

字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)

insertStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)

updateStrategy

Enum

FieldStrategy.DEFAULT

举例:IGNORED update table_a set column=#{columnProperty}

whereStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>

fill

Enum

FieldFill.DEFAULT

字段自动填充策略

select

boolean

true

是否进行 select 查询

keepGlobalFormat

boolean

false

是否保持使用全局的 format 进行处理

jdbcType

JdbcType

JdbcType.UNDEFINED

JDBC 类型 (该默认值不代表会按照该值生效)

typeHandler

TypeHander

类型处理器 (该默认值不代表会按照该值生效)

numericScale

String

""

指定小数点后保留的位数

2.常见配置

MybatisPlus也支持基于yaml文件的自定义配置,详见官方文档:

https://www.baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE

大多数的配置都有默认值,因此我们都无需配置。但还有一些是没有默认值的,例如:

  • 实体类的别名扫描包

  • 全局id类型

mybatis-plus:
  type-aliases-package: com.scau.mp.domain.po
  global-config:
    db-config:
      id-type: auto # 全局id类型为自增长

需要注意的是,MyBatisPlus也支持手写SQL的,而mapper文件的读取地址可以自己配置:

mybatis-plus:
  mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。

3.BaseMapper的基础CRUD方法

官方文档案例如下:https://baomidou.com/pages/49cc81/#mapper-crud-接口

代码测试用例:

@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo01_BaseMapper的基本CURD {

    @Autowired
    private UserMapper userMapper;

    /**
     * 新增
     * INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
     */
    @Test
    public void insert() {
        User user = new User(100L, "Ken", "0",20);
        userMapper.insert(user);
    }

    /**
     * 修改
     * UPDATE user SET name=?, age=?, email=? WHERE id=?
     */
    @Test
    public void update() {
        User user = new User(100L, "Kevin", "0", 25);
        userMapper.updateById(user);
    }


    /**
     * 根据id查询
     * SELECT id,name,age,email FROM user WHERE id=?
     */
    @Test
    public void selectById() {
        User user = userMapper.selectById(100L);
        System.out.println(user);
    }

    /**
     * 根据一批id查询
     * SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
     */
    @Test
    public void selectBatchIds() {
        List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        for (User user : userList) {
            System.out.println(user);
        }
    }

    /**
     * 根据条件查询数据
     * SELECT id,name,age,email FROM user WHERE name = ? AND id = ?
     */
    @Test
    public void selectByMap() {
        // 封装条件
        HashMap<String, Object> param = new HashMap<>();
        param.put("id",10L);
        param.put("name","Kevin");

        // 根据条件查询,map中的多个条件是并列关系 id=10 and name='小灰灰'
        List<User> userList = userMapper.selectByMap(param);
        for (User user : userList) {
            System.out.println(user);
        }
    }

    /**
     * 根据id删除
     * DELETE FROM user WHERE id=?
     */
    @Test
    public void deleteById() {
        userMapper.deleteById(100L);
    }

    /**
     * 根据id删除一批
     * DELETE FROM user WHERE id IN ( ? , ? , ? )
     */
    @Test
    public void deleteBatchIds() {
        userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
    }

    /**
     * 根据条件删除数据
     * DELETE FROM user WHERE name = ? AND id = ?
     */
    @Test
    public void deleteByMap() {
        // 封装条件
        HashMap<String, Object> param = new HashMap<>();
        param.put("id",100L);
        param.put("name","Kevin");

        userMapper.deleteByMap(param);
    }
}

4.Wrapper的使用(条件构造器)

通过BaseMapper提供的一些方法我们可以完成一些基本的CRUD,但无法完成复杂条件的查询;对于复杂条件的查询,MyBatis Plus提供了Wrapper接口来处理;

Wrapper是MyBatis Plus提供的一个条件构造器,主要用于构建一系列条件,当Wrapper构建完成后,可以使用Wrapper中的条件进行查询、修改、删除等操作;

官方文档如下:条件构造器 | MyBatis-Plus

Wrapper是条件构造抽象类,最顶端父类,其主要实现类有如下:

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

        QueryWrapper : Query条件封装
        UpdateWrapper : Update条件封装
        AbstractLambdaWrapper : 使用Lambda语法
                LambdaQueryWrapper :基于Lambda语法使用的查询Wrapper
                LambdaUpdateWrapper : 基于Lambda语法使用的更新Wrapper

4.1Wrapper的方法集

方法名解释示例
eq等于 =eq("name", "老王") ---> name = '老王' 
ne不等于 <>ne("name", "老王") ---> name <> '老王' 
gt大于 >gt("age", 18) ---> age > 18 
ge大于等于 >=ge("age", 18) ---> age >= 18 
lt小于 <lt("age", 18) ---> age < 18 
le小于等于 <=le("age", 18) ---> age <= 18 
betweenbetween 值1 and 值2between("age", 18, 30) ---> age between 18 and 30 
notBetweennot between 值1 and 值2notBetween("age", 18, 30) ---> age not between 18 and 30 
likeLIKE ‘%值%’like("name", "王") ---> name like '%王%' 
notLikeNOT LIKE ‘%值%’notLike("name", "王") ---> name not like '%王%' 
likeLeftLIKE ‘%值’likeLeft("name", "王") ---> name like '%王' 
likeRightLIKE ‘值%’likeRight("name", "王") ---> name like '王%' 
isNull字段 IS NULLisNull("name") ---> name is null 
isNotNull字段 IS NOT NULLisNotNull("name") ---> name is not null 
in字段 IN (v0, v1, …)in("age", 1, 2, 3) ---> age in (1,2,3) 
notIn字段 NOT IN (v0, v1, …)notIn("age", 1, 2, 3) ---> age not in (1,2,3) 
inSql字段 IN ( sql语句 )inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3) 
notInSql字段 NOT IN ( sql语句 )notInSql("id", "select id from table where id < 3") ---> id not in (select id from table where id < 3) 
groupBy分组:GROUP BY 字段, …groupBy("id", "name") ---> group by id,name 
orderByAsc排序:ORDER BY 字段, … ASCorderByAsc("id", "name") ---> order by id ASC,name ASC 
orderByDesc排序:ORDER BY 字段, … DESCorderByDesc("id", "name") ---> order by id DESC,name DESC 
havingHAVING ( sql语句 )having("sum(age) > {0}", 11) ---> having sum(age) > 11 
func主要解决条件拼接func(i -> if(true) {i.eq("id", 1)} else {i.ne ("id", 1)}) 
or拼接 OReq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王' 

这些方法不用背,要构造Wrapper的时候查官方文档即可:

条件构造器 | MyBatis-Plus

4.2QueryWapper的使用

创建Wrapper对象:

  • Wrappers静态方法:
    • public static <T> QueryWrapper<T> query()
  • 通过QueryWrapper对象的构造方法:
    • public QueryWrapper()

代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo02_Wrapper基本方法 {

    @Autowired
    private UserMapper userMapper;

    /**
     * QueryMapper的创建
     * SELECT id,name,age,email FROM user
     */
    @Test
    public void test1() {
        // 创建QueryMapper,默认情况下查询所有数据
        QueryWrapper<User> wrapper = Wrappers.query();
        QueryWrapper<User> wrapper2 = new QueryWrapper<>();

        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

其他方法的使用:

@Test
public void test2() {
    QueryWrapper<User> wrapper = Wrappers.query();
    // name ='Jack'
//        wrapper.eq("name","Jack");

    /*
    	参数1: 是否要进行name条件的拼接
    */
    String name = "Jack";
    wrapper.eq(name != null, "name", name);
    
    // name != 'Jack'
//        wrapper.ne("name","Jack");

    // age > 20
//        wrapper.gt("age",20);

    // age < 20
//        wrapper.lt("age",20);

    // age=20
//        wrapper.lt("age",20);

    // age between 20 and 24
//        wrapper.between("age",20,24);

    // age not between 20 and 24
//        wrapper.notBetween("age",20,24);

    // name like "%J%"          自动拼接左右的%
//        wrapper.like("name","J");

    // name not like "%J%"
//        wrapper.notLike("name","J");

    // name like "%J"
//        wrapper.likeLeft("name","J");

    // name like 'J%'
//        wrapper.likeRight("name","J");

    // name is null
//        wrapper.isNull("name");

    // name is not null
//        wrapper.isNotNull("name");

    // name in ('Jack','Tom','Jone')
//        wrapper.in("name","Jack","Tom","Jone");

    // name not in ('Jack','Tom','Jone')
//        wrapper.notIn("name","Jack","Tom","Jone");
    
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

4.3UpdateWrapper的使用

代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo05_UpdateWrapper {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1() throws Exception {
        UpdateWrapper<User> wrapper = Wrappers.update();

        // UpdateWrapper也是AbstractWrapper的子类,因此也具备一些基本的查询方法
        wrapper.like("name", "J");

        List<User> userList = userMapper.selectList(wrapper);

        for (User user : userList) {
            System.out.println(user);
        }
    }


    /**
     * 第一种方法: 使用wrapper来修改,并且指定查询条件
     *
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        UpdateWrapper<User> wrapper = Wrappers.update();
        wrapper.set("name", "Jackson");
        wrapper.set("age", "16");
        wrapper.set("sex", "1");
        wrapper.eq("id", 2L);

        // SQL: UPDATE user SET name=?, sex=?, age=? WHERE (id = ?)
        userMapper.update(null, wrapper);
    }


    /**
     * 第二种方法: 使用wrapper来封装条件,使用entity来封装修改的数据
     *
     * @throws Exception
     */
    @Test
    public void test3() throws Exception {
        UpdateWrapper<User> wrapper = Wrappers.update();
        wrapper.eq("id", 2L);

        User user = new User(null, "Jack", "0", 28);

        // SQL: UPDATE user SET name=?, sex=?, age=? WHERE (id = ?)
        userMapper.update(user, wrapper);

    }

    /**
     * 第三种方法: Wrappers.update(user)传递查询的条件,使用wrapper来修改
     *
     * @throws Exception
     */
    @Test
    public void test4() throws Exception {
        User user = new User();
        user.setId(1L);

        // user当做查询条件
        UpdateWrapper<User> wrapper = Wrappers.update(user);
        wrapper.set("name", "xiaohui");
        wrapper.set("sex", "0");
        wrapper.set("age", "22");

        // SQL : UPDATE user SET name=?,sex=?,age=? WHERE id=?
        userMapper.update(null, wrapper);
    }

    /**
     * setSql方法
     *
     * @throws Exception
     */
    @Test
    public void test5() throws Exception {
        UpdateWrapper<User> wrapper = Wrappers.update();
        wrapper.setSql("name='abc',sex='0',age=18 where id=1");

        // SQL: UPDATE user SET name='abc',sex='0',age=18 where id=1
        userMapper.update(null, wrapper);
    }
}

4.4LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。 那怎么样才能不写字段名,又能知道字段名呢?

其中一种办法是基于变量的gettter方法结合反射技术。因此我们只要将条件对应的字段的getter方法传递给MybatisPlus,它就能计算出对应的变量名了。而传递方法可以使用JDK8中的方法引用Lambda表达式。 因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:

  • LambdaQueryWrapper

  • LambdaUpdateWrapper

分别对应QueryWrapper和UpdateWrapper

@Test
void testLambdaQueryWrapper() {
    // 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lambda()
            .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000);
    // 2.查询
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.Mapper分页查询

在MyBatis中提供有Page对象来帮助我们实现分页查询,在Page对象中有如下成员:

方法描述
getRecords()查询当前页的数据记录,返回类型是列表 
getCurrent()返回当前页码 
getTotal()获取总记录数 
getSize()获取页面大小 
getPages()获取总页数 
hasPrevious()判断当前页是否有上一页 
hasNext()判断当前页是否有下一页 

而在MybatisPlus中则是使用分页插件来实现分页查询的,因此我们首先要配置MyBatisPlus的分页插件;

  • 配置分页插件:

@Configuration
@MapperScan("com.scau.mapper")          // mapper接口的所在位置
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

在BaseMapper中主要提供有如下方法来完成分页查询:

<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper):


参数1:分页配置类
参数2:分页查询条件
解释:根据分页配置和分页查询条件来完成分页查询,当前页数据为指定类型

<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper)


参数1:分页配置类
参数2:分页查询条件
解释:根据分页配置和分页查询条件来完成分页查询,当前页数据为Map类型

  • 1)无条件分页查询:

@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo06_BaseMapper的分页查询 {

    @Autowired
    private UserMapper userMapper;

    /**
     * 无条件分页查询
     * @throws Exception
     */
    @Test
    public void test1() throws Exception {

        // 封装分页信息
        Page<User> page = new Page<>(1,3);

        /*
         执行分页查询,并将结果封装到page中
            参数1: 分页配置
            参数2: 查询条件
         */
        userMapper.selectPage(page, null);

        // 当前页数据
        List<User> pageData = page.getRecords();
        for (User user : pageData) {
            System.out.println(user);
        }

        System.out.println("------------");

        System.out.println("当前页:" + page.getCurrent());
        System.out.println("每页显示的条数:" + page.getSize());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("总页数:" + page.getPages());
        System.out.println("是否有上一页:" + page.hasPrevious());
        System.out.println("是否有下一页:" + page.hasNext());
    }
}

查询结果如下:

# 首先查询总记录数
==>  Preparing: SELECT COUNT(*) FROM user
==> Parameters: 
<==    Columns: COUNT(*)
<==        Row: 10
<==      Total: 1

# 再查询分页
==>  Preparing: SELECT id,name,sex,age FROM user LIMIT ?
==> Parameters: 3(Long)
<==    Columns: id, name, sex, age
<==        Row: 1, Jone, 1, 27
<==        Row: 2, Jack, 0, 20
<==        Row: 3, Tom, 1, 28
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@226eba67]
User(id=1, name=Jone, sex=1, age=27)
User(id=2, name=Jack, sex=0, age=20)
User(id=3, name=Tom, sex=1, age=28)
------------
当前页:1
每页显示的条数:3
总记录数:10
总页数:4
是否有上一页:false
是否有下一页:true
2022-11-15 15:28:16.946  INFO 8724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-11-15 15:28:16.948  INFO 8724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

2)带条件查询

/**
 * 带条件分页查询
 *
 * @throws Exception
 */
@Test
public void test2() throws Exception {

    QueryWrapper<User> wrapper = Wrappers.query();
    wrapper.like("name", "a");

    // 封装分页信息
    Page<User> page = new Page<>(1, 3);

    /*
     执行分页查询,并将结果封装到page中
        参数1: 分页配置
        参数2: 查询条件
     */
    userMapper.selectPage(page, wrapper);

    // 当前页数据
    List<User> pageData = page.getRecords();
    for (User user : pageData) {
        System.out.println(user);
    }

    System.out.println("------------");

    System.out.println("当前页:" + page.getCurrent());
    System.out.println("每页显示的条数:" + page.getSize());
    System.out.println("总记录数:" + page.getTotal());
    System.out.println("总页数:" + page.getPages());
    System.out.println("是否有上一页:" + page.hasPrevious());
    System.out.println("是否有下一页:" + page.hasNext());
}

查询结果如下:

==>  Preparing: SELECT COUNT(*) FROM user WHERE (name LIKE ?)
==> Parameters: %a%(String)
<==    Columns: COUNT(*)
<==        Row: 5
<==      Total: 1
==>  Preparing: SELECT id,name,sex,age FROM user WHERE (name LIKE ?) LIMIT ?
==> Parameters: %a%(String), 3(Long)
<==    Columns: id, name, sex, age
<==        Row: 2, Jack, 0, 20
<==        Row: 4, Sandy, 1, 21
<==        Row: 6, Jackson, 0, 18
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@58a2b4c]
User(id=2, name=Jack, sex=0, age=20)
User(id=4, name=Sandy, sex=1, age=21)
User(id=6, name=Jackson, sex=0, age=18)
------------
当前页:1
每页显示的条数:3
总记录数:5
总页数:2
是否有上一页:false
是否有下一页:true

3)将分页结果以map的形式返回

/**
 * 查询结果以Map返回
 *
 * @throws Exception
 */
@Test
public void test3() throws Exception {

    // 封装分页信息
    Page page = new Page<>(1, 3);

    userMapper.selectMapsPage(page, null);

    // 每一条记录都是一个HashMap
    List<HashMap<String,Object>> pageData = page.getRecords();
    for (HashMap userMap : pageData) {
        System.out.println(userMap);
    }

    System.out.println("------------");

    System.out.println("当前页:" + page.getCurrent());
    System.out.println("每页显示的条数:" + page.getSize());
    System.out.println("总记录数:" + page.getTotal());
    System.out.println("总页数:" + page.getPages());
    System.out.println("是否有上一页:" + page.hasPrevious());
    System.out.println("是否有下一页:" + page.hasNext());
}

6.MyBatis Plus的Service查询

通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行、remove删除、list 查询集合、page查询分页

架构图如下:

使用步骤:

  • 1)定义一个UserService接口继承与MyBatisPlus提供的IService接口:

public interface IUserService extends IService<User> {
}
  • 2)定义一个UserService的实现类,并且继承与MyBatisPlus提供的ServiceImpl:
  • 
    @Service("userService")
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    
    }
    

    常用的service方法集:

  • 新增:

 default boolean save(T entity):新增记录

boolean saveBatch(Collection<T> entityList):批量插入

saveBatch(Collection<T> entityList, int batchSize):一次性批量插入batchSize条记录

  • 删除:

boolean removeById(Serializable id):根据id删除

boolean removeByMap(Map<String, Object> columnMap):根据条件删除

boolean remove(Wrapper<T> queryWrapper):使用Wrapper封装条件删除

boolean removeByIds(Collection<? extends Serializable> idList):删除一批

  • 修改:

boolean updateById(T entity):修改

boolean update(Wrapper<T> updateWrapper):根据Wrapper修改

boolean update(T entity, Wrapper<T> updateWrapper):使用Wrapper查询出结果,修改为entity

boolean updateBatchById(Collection<T> entityList):批量修改

updateBatchById(Collection<T> entityList, int batchSize):一次性批量修改batchSize条记录

boolean saveOrUpdate(T entity):如果id存在则修改,如果id不存在则新增

  • 查询:

T getById(Serializable id):根据id查询

List<T> listByIds(Collection<? extends Serializable> idList):根据一批id查询多条记录

List<T> listByMap(Map<String, Object> columnMap):根据条件查询多条记录

T getOne(Wrapper<T> queryWrapper):根据Wrapper查询一条记录,如果查询到多条则抛出异常

T getOne(Wrapper<T> queryWrapper, boolean throwEx):根据Wrapper查询一条记录,通过throwEx决定是否抛出异常

int count():查询总记录数

int count(Wrapper<T> queryWrapper):根据条件查询总记录数

  • 分页:

<E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper):带条件分页查询,当前页数据为T类型

<E extends IPage<T>> E page(E page):无条件分页

List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper):带条件分页查询,当前页数据为HashMap类型

List<Map<String, Object>> listMaps():无条件分页

测试代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo07_Service查询 {

    @Autowired
    private IUserService userService;

    /**
     * 新增
     *
     * @throws Exception
     */
    @Test
    public void test1() throws Exception {
        User user = new User(null, "xiaohui", "0", 20);
        userService.save(user);
    }

    /**
     * 如果id存在则修改,不存在则新增
     *
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        User user = new User(1L, "xiaohui", "0", 20);
        userService.saveOrUpdate(user);
    }

    /**
     * 根据id删除
     *
     * @throws Exception
     */
    @Test
    public void test3() throws Exception {
        userService.removeById(1L);
    }

    /**
     * 根据id修改
     *
     * @throws Exception
     */
    @Test
    public void test4() throws Exception {

        User user = new User(1L, "xiaolan", "1", 18);
        userService.updateById(user);
    }

    /**
     * 根据id查询
     *
     * @throws Exception
     */
    @Test
    public void test5() throws Exception {
        User user = userService.getById(1L);
        System.out.println(user);
    }

    /**
     * 查询列表
     *
     * @throws Exception
     */
    @Test
    public void test6() throws Exception {

        QueryWrapper<User> wrapper = Wrappers.query();
        wrapper.in("id", "1", "2");

        // 查询所有
//        List<User> userList = userService.list();

        // 通过wrapper查询
        List<User> userList = userService.list(wrapper);

        for (User user : userList) {
            System.out.println(user);
        }
    }


    /**
     * 查询总记录数
     *
     * @throws Exception
     */
    @Test
    public void test7() throws Exception {

        QueryWrapper<User> wrapper = Wrappers.query();
        wrapper.like("name", "a");

        // 查询总记录数
//        int count = userService.count();

        // 根据条件查询总记录数
        int count = userService.count(wrapper);

        System.out.println(count);
    }

    /**
     * 分页查询(当前页类型为指定类型)
     *
     * @throws Exception
     */
    @Test
    public void test8() throws Exception {

        Page<User> page = new Page<>(1, 3);

        userService.page(page);

        // 当前页数据
        List<User> pageData = page.getRecords();
        for (User user : pageData) {
            System.out.println(user);
        }

        System.out.println("------------");

        System.out.println("当前页:" + page.getCurrent());
        System.out.println("每页显示的条数:" + page.getSize());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("总页数:" + page.getPages());
        System.out.println("是否有上一页:" + page.hasPrevious());
        System.out.println("是否有下一页:" + page.hasNext());
    }


    /**
     * 分页查询(当前页结果为HashMap类型)
     *
     * @throws Exception
     */
    @Test
    public void test9() throws Exception {

        Page page = new Page<>(1, 3);

        userService.pageMaps(page);

        // 当前页数据
        List<HashMap<String, Object>> pageData = page.getRecords();
        for (HashMap userMap : pageData) {
            System.out.println(userMap);
        }

        System.out.println("------------");

        System.out.println("当前页:" + page.getCurrent());
        System.out.println("每页显示的条数:" + page.getSize());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("总页数:" + page.getPages());
        System.out.println("是否有上一页:" + page.hasPrevious());
        System.out.println("是否有下一页:" + page.hasNext());
    }


    /**
     * 链式查询
     *
     * @throws Exception
     */
    @Test
    public void test10() throws Exception {

        QueryChainWrapper<User> chainWrapper = userService.query();

        // SQL: SELECT id,name,age FROM user WHERE (id IN (?,?,?) AND name LIKE ?)
        List<User> userList = chainWrapper.select("id", "name", "age")
                .in("id", "1", "2", "3")
                .like("name", "a")
                .list();

        for (User user : userList) {
            System.out.println(user);
        }
    }


    /**
     * 链式修改
     *
     * @throws Exception
     */
    @Test
    public void test11() throws Exception {

        UpdateChainWrapper<User> chainWrapper = userService.update();

        // SQL: UPDATE user SET age=? WHERE (id IN (?,?) OR sex = ?)
        chainWrapper.in("id","1","2")
                .or()
                .eq("sex","0")
                .set("age",20).
                update();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值