4 Mybatis-Plus通用CRUD

通过前面的学习,我们了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这 些操作,下图是BaseMapper的各各方法:

4.1 插入操作

4.1.1 方法定义

/**
* 插入一条记录
* @param entity 实体对象
*/
int insert(T entity);

4.1.2 测试用例

package  cn.yh.mp;
import   cn.yh.mp.mapper.UserMapper; 
import   cn.yh.mp.pojo.User;
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.SpringRunner;
import   java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert() {
        User user = new User();
        user.setAge(20);
        user.setEmail("test@yh.cn");
        user.setName("曹操");
        user.setUserName("caocao");
        user.setPassword("123456");
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd   HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse("1990-01-01   00:00:00", df);
        user.setBirthday(localDateTime);
        int result = this.userMapper.insert(user);   //返回的result是受影响的行数,并不是自增后的id
        System.out.println("result = " + result);
        System.out.println(user.getId());   //自增后的id会回填到对象中
    }
}

4.1.3 MP主键生成策略

上例中Mybatis-plus自动生成ID,如何设置id的生成策略呢?

MP支持的id策略如下:

package com.baomidou.mybatisplus.annotation;
import lombok.Getter;
/**
* 生成ID类型枚举类
*
* @author hubin
* @since 2015-11-10
*/
@Getter
public enum IdType {
    /**
    * 数据库ID自增
    */
    AUTO(0),
    /**
    * 该类型为未设置主键类型
    */
    NONE(1),
    /**
    * 用户输入ID
    * <p>该类型可以通过自己注册自动填充插件进行填充</p>
    */
    INPUT(2),
    /**
    * 全局唯一ID (idWorker)
    */
    ID_WORKER(3),
    /**
    * 全局唯一ID (UUID)
    */
    UUID(4),
    /**
    * 字符串全局唯一ID (idWorker 的字符串表示)
    */
    ID_WORKER_STR(5);
    private final int key;
    IdType(int key) {
        this.key = key;
    }
}

1 自增主键:

完全采用数据库自增主键方式。

1)设置mysql数据库主键为自增

2)修改User对象:

@TableId(value = "ID", type = IdType.AUTO)
private Long id;
或:
@TableId(value = "ID")
private Long id;

3)程序中不用设置主键

2 输入主键:

手动设置主键值。

1)mysql数据库主键为自增或不是自增都可以

2)修改User对象:

@TableId(value = "ID",type = IdType.INPUT)
private Long id;

3)程序中需要设置主键

3 UUID:

生成全局唯一ID。

1)mysql数据库主键为字符串类型,不是自增类型。

2)修改User对象。

@TableId(value = "ID",type = IdType.UUID)
private String id;

3)程序中不用设置主键

4 ID_WORKER_STR:

采用雪花算法(雪花算法生成的ID是纯数字且具有时间顺序,适合分布式场景)生成全局唯一ID,字符串类型。

1)mysql数据库主键为字符串类型,不是自增类型。

2)修改User对象。

@TableId(value = "ID",type = IdType.ID_WORKER_STR)
private String id;

3)程序中不用设置主键

5 ID_WORKER:

采用雪花算法生成全局唯一ID,数值类型。

1)mysql数据库主键为数值类型,不是自增类型。

2)修改User对象。

@TableId(value = "ID",type = IdType.ID_WORKER)
private Long id;

3)程序中不用设置主键

4.2 更新操作

4.2.1 根据id更新

方法定义:

/**
* 根据 ID 修改
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);

根据id更新操作步骤:

1 首先需要设置对象的主键属性值。

2 再设置要更新的属性值。

3 根据主键找到对象,更新设置属性值。

4 返回影响的记录数。

注意:只能将对象中不为NULL的属性更新到表中。测试:

// 根据id 更新
@Test
public void testUpdateById() {
    User user = new User();
    user.setId(7L); //主键
    user.setAge(21); //更新的字段
    //根据id更新,更新不为null的字段
    this.userMapper.updateById(user);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Preparing: UPDATE tb_user SET
age=? WHERE id=?
[main] [cn.yh.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Parameters: 21(Integer), 6(Long)
[main] [cn.yh.mp.mapper.UserMapper.updateById]-[DEBUG] <== Updates: 1

4.2.2 根据条件更新

方法定义:

/**
* 根据 whereEntity 条件,更新记录
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, 
           @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

根据ID更新 一次只能更新一条记录,根据条件更新可实现批量更新。

根据条件更新步骤:

1 在对象中设置要更新的属性值。

2 设置QueryWrapper,设置更新条件,可以设置多个。

3 返回影响的记录数。

注意:只能将对象中不为NULL的属性更新到表中。

测试用例:

将name等于“曹操”的记录全部更新。

@Test
public void testUpdate() {
    User user = new User();
    user.setAge(22);   //更新的字段
    //更新的条件
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name",   "曹操");
    //可以设置多个条件...

    //执行更新操作 UPDATE tb_user SET age=22 WHERE name = '曹操'
    int result = this.userMapper.update(user,wrapper);
    System.out.println("result   =   "   +   result);
}

上边根据id更新 根据条件更新的方法只能将对象中不为NULL的属性更新到表中,

下边通过UpdateWrapper进行更新,将birthday字段更新为NULL.

@Test
public void testUpdate2()   {
    //更新的条件以及字段
    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", 7).set("age", 23).set("birthday",null);

    //执行更新操作  UPDATE tb_user SET age=23,birthday=null WHERE id = 7
    int result = this.userMapper.update(null, wrapper);
    System.out.println("result   =   "   +   result);
}

MybatisPlus的UpdateWrapper和QueryWrapper的区别:

对于查询来说,两者基本没啥区别,一般查询都是QueryWrapper;
QueryWrapper可以根据id修改,也可以根据QueryWrapper构建的推荐查询进行修改,后者修改传入一个映射实体,而且默认不会把映射实体的控制映射到数据库中;
如果想将数据库某个属性设置为null,使用UpdateWrapper

4.3 删除操作

4.3.1 deleteById

方法定义:

/**
*   根据  ID   删除
*   @param   id   主键ID
*/
int deleteById(Serializable id);

操作步骤:

1 指定要删除记录的主键值。

2 调用deleteById方法执行删除。

测试用例:

@Test
public void testDeleteById() {
    //执行删除操作
    int   result   =   this.userMapper.deleteById(7L);
    System.out.println("result   =   "   +   result);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Preparing: DELETE FROM tb_user WHERE id=?
[main] [cn.yh.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Parameters: 6(Long) [main] [cn.yh.mp.mapper.UserMapper.deleteById]-[DEBUG] <==   Updates: 1

4.3.2 delete

方法定义:

/**
*   根据 entity 条件,删除记录
*   @param wrapper 实体对象封装操作类(可以为 null)
*/
int   delete(@Param(Constants.WRAPPER)   Wrapper<T>   wrapper);

根据条件删除步骤:

1 定义对象,设置属性值,指定删除条件 ,可指定多个删除条件

注意:删除条件只匹配对象中不为NULL的属性值

2 设置QueryWrapper

3 执行删除

测试用例:

// 根据条件删除
@Test
public void testDeleteByMap() {
    User   user   =   new   User();
    user.setAge(20);
    user.setName("刘备");
    //将实体对象进行包装,包装为操作条件
    QueryWrapper<User>  wrapper  =  new   QueryWrapper<>(user);
    int   result   =   this.userMapper.delete(wrapper);
    System.out.println("result   =   "   +   result);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.delete]-[DEBUG] ==> Preparing:  DELETE  FROM  tb_user  WHERE name=? AND age=?
[main] [cn.yh.mp.mapper.UserMapper.delete]-[DEBUG] ==> Parameters: 张三(String), 20(Integer)
[main] [cn.yh.mp.mapper.UserMapper.delete]-[DEBUG]  <== Updates: 0

注意:

定义QueryWrapper可以不包装模型对象,手动设置条件,如下:

QueryWrapper<User> wrapper = new QueryWrapper<>(); 
wrapper.eq("age",20);
wrapper.eq("name","张三");

4.3.3 deleteBatchIds

方法定义:

/**
* 删除(根据ID批量删除)
* @param idList 主键ID列表(不能为null以及empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

批量删除操作步骤:

1 指定 id列表

2 执行删除

测试用例:

// 根据id 批量删除
@Test
public void testDeleteByIds() {
    //根据id集合批量删除 DELETE FROM tb_user WHERE ID IN ( ? , ? , ? )
    int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));
    System.out.println("result = "+ result);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] ==> Preparing: DELETE FROM tb_user WHERE id IN ( ? , ? , ? )
[main] [cn.yh.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] ==> Parameters: 1(Long), 10(Long), 20(Long)
[main] [cn.yh.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] <==  Updates: 1

4.4 查询操作

MP提供了多种查询操作,包括根据id查询 批量查询 查询单条数据 查询列表 分页查询等操作。

4.4.1 selectById

方法定义:

/**
* 根据 ID 查询
* @param id 主键ID
*/
T selectById(Serializable id);

根据id查询步骤:

1 设置查询记录的主键值。

2 执行查询。

3 查询结果返回一个对象。

测试用例:

// 根据id 查询
@Test
public void testSelectById() {
    //根据id查询数据
    User user = this.userMapper.selectById(2L);
    System.out.println("result = " + user);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.selectById]-[DEBUG] ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE id=?
[main] [cn.yh.mp.mapper.UserMapper.selectById]-[DEBUG] ==> Parameters: 2(Long) [main] [cn.yh.mp.mapper.UserMapper.selectById]-[DEBUG] <==   Total: 1
result   =   User(id=2,   userName=lisi,   password=123456,   name=李四,   age=20,   email=test2@yh.cn, address=null)

4.4.2 selectBatchIds

方法定义:

/**
* 查询(根据ID批量查询)
* @param idList 主键ID列表(不能为null以及empty)
*/
List<T>   selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

根据id列表查询:

1 设置id列表

2 执行查询

3 查询对象返回List

测试用例:

// 根据多个id 查询
@Test
public void testSelectBatchIds() {
    //根据id集合批量查询
    List<User> users = this.userMapper
        .selectBatchIds(Arrays.asList(2L, 3L, 10L));
    for (User user : users)   {
        System.out.println(user);
    }
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.selectBatchIds]-[DEBUG] ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE id IN ( ? , ? , ? )
[main] [cn.yh.mp.mapper.UserMapper.selectBatchIds]-[DEBUG] ==> Parameters: 2(Long), 3(Long), 10(Long)
[main] [cn.yh.mp.mapper.UserMapper.selectBatchIds]-[DEBUG] <==  Total: 2

User(id=2,   userName=lisi,   password=123456,   name=李四,   age=20,   email=test2@yh.cn, address=null)
User(id=3,   userName=wangwu,   password=123456,   name=王五,   age=28,   email=test3@yh.cn,
address=null)

4.4.3 selectOne

方法定义:

/**
*   根据 entity 条件,查询一条记录
*   @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

查询步骤:

1 设置QueryWrapper对象,设置查询条件,可以设置多个条件

2 执行查询

注意:如果查询结果为多条记录则报错(TooManyResultsException)。

测试用例:

// 查询 返回一条结果
@Test
public void testSelectOne() {
    QueryWrapper<User> wrapper = new QueryWrapper<User>(); 
    wrapper.eq("name", "李四");
    //根据条件查询一条数据,如果结果超过一条会报错
    User user = this.userMapper.selectOne(wrapper);
    System.out.println(user);
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.selectOne]-[DEBUG] ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ?
[main] [cn.yh.mp.mapper.UserMapper.selectOne]-[DEBUG] ==> Parameters: 李四(String)
[main] [cn.yh.mp.mapper.UserMapper.selectOne]-[DEBUG] <==   Total: 1
User(id=2,   userName=lisi,   password=123456,   name=李四,   age=20,   email=test2@yh.cn, address=null)

4.4.4 selectCount

方法定义:

/**
*   根据 Wrapper 条件,查询总记录数
*   @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer   selectCount(@Param(Constants.WRAPPER)   Wrapper<T>   queryWrapper);

测试用例:

// 查询记录数
@Test
public void testSelectCount() {
    QueryWrapper<User> wrapper = new QueryWrapper<User>(); 
    wrapper.gt("age", 23);   //年龄大于23岁
    //根据条件查询数据条数
    Integer   count   =   this.userMapper.selectCount(wrapper);
    System.out.println("count   =   "   +   count);
}

结果:

[main]  [cn.yh.mp.mapper.UserMapper.selectCount]-[DEBUG]  ==>  Preparing:  SELECT  COUNT(   1   )   FROM tb_user WHERE age > ?
[main] [cn.yh.mp.mapper.UserMapper.selectCount]-[DEBUG] ==> Parameters: 23(Integer) [main] [cn.yh.mp.mapper.UserMapper.selectCount]-[DEBUG] <== Total: 1
count = 2

4.4.5 selectList

方法定义:

/**
*   根据 entity 条件,查询全部记录
*   @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T>   selectList(@Param(Constants.WRAPPER)   Wrapper<T>   queryWrapper);

测试用例

@Test
public void testSelectList() {
    QueryWrapper<User>  wrapper = new QueryWrapper<User>(); 
    wrapper.gt("age",   23);   //年龄大于23岁

    //根据条件查询数据
    List<User>   users   =   this.userMapper.selectList(wrapper); 
    for   (User   user   :   users)   {
        System.out.println("user   =   "   +   user);
    }
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.selectList]-[DEBUG] ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE age > ?
[main] [cn.yh.mp.mapper.UserMapper.selectList]-[DEBUG] ==> Parameters: 23(Integer) [main]  [cn.yh.mp.mapper.UserMapper.selectList]-[DEBUG]  <== Total: 2

user   =   User(id=3,   userName=wangwu,   password=123456,   name=王五,   age=28,   email=test3@yh.cn, address=null)
user   =   User(id=5,   userName=sunqi,   password=123456,   name=孙七,   age=24,   email=test5@yh.cn, address=null)

4.4.6 selectPage

方法定义:

/**
*   根据 entity 条件,查询全部记录(并翻页)
*
*   @param page 分页查询条件(可以为 RowBounds.DEFAULT)
*   @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T>   selectPage(IPage<T>   page,   @Param(Constants.WRAPPER)   Wrapper<T>   queryWrapper);

配置分页插件:

package com.laojun.mp.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName : MybatisPlusConfig
 * @Author : glls
 * @Date: 2021/2/23 11:45
 * @Description : 配置
 */
@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() { 
        return new PaginationInterceptor();
    }
}

测试用例:

// 测试分页
@Test
public void testSelectPage() {
    QueryWrapper<User> wrapper = new QueryWrapper<User>();
    wrapper.gt("age", 20); //年龄大于20岁

    //参数1:当前页码,小于1的按1算
    //参数2:每页记录数
    Page<User> page = new Page<>(1,2);

    //根据条件查询数据
    IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
    System.out.println("数据总条数:" + iPage.getTotal());
    System.out.println("总页数:" + iPage.getPages());

    //取出分页记录
    List<User> users = iPage.getRecords(); 
    for (User user : users) {
        System.out.println("user = " + user);
    }
}

结果:

[main] [cn.yh.mp.mapper.UserMapper.selectPage]-[DEBUG] ==> Preparing: SELECT COUNT(1) FROM tb_user WHERE age > ?
[main] [cn.yh.mp.mapper.UserMapper.selectPage]-[DEBUG] ==> Parameters: 20(Integer) [main] [cn.yh.mp.mapper.UserMapper.selectPage]-[DEBUG] ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE age > ? LIMIT ?,?
[main] [cn.yh.mp.mapper.UserMapper.selectPage]-[DEBUG] ==> Parameters: 20(Integer), 0(Long), 1(Long)
[main] [cn.yh.mp.mapper.UserMapper.selectPage]-[DEBUG] <==  Total: 1
[main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ecd665]
数据总条数:3
总页数:3
user   =   User(id=3,   userName=wangwu,   password=123456,   name=王五,   age=28,   email=test3@yh.cn,
birthday=2019-10-02T11:42:14,   address=null)