Mybatis-Plus:通用CRUD、设置Mybatis-Plus Id的生成策略、@TableField(属性名和字段名不一致、字段不存在、忽略字段)

发布于:2023-01-09 ⋅ 阅读:(322) ⋅ 点赞:(0)

本节案例承接上节案例

通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这些操作。

BaseMapper.java源码

/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.core.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * <p>这个 Mapper 支持 id 泛型</p>
 *
 * @author hubin
 * @since 2016-01-23
 */
public interface BaseMapper<T> extends Mapper<T> {

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

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

    /**
     * 根据 columnMap 条件,删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

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

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

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

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

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

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

    /**
     * 查询(根据 columnMap 条件)
     *
     * @param columnMap 表字段 map 对象
     */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

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

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

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

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

    /**
     * 根据 Wrapper 条件,查询全部记录
     * <p>注意: 只返回第一个字段的值</p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

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

    /**
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}


1 插入操作


1.1 方法定义

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

1.2 编写测试用例

在这里插入图片描述

TestUserMapper.java

package com.tian.springbootmybatis_plus;

import mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import pojo.User;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestUserMapper {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert() {
        User user = new User();
        user.setAge(301);
        user.setUserName("caocao1");
        user.setName("曹操1");
        user.setPassword("123456");
        int result = this.userMapper.insert(user); //result数据库受影响的行数
        System.out.println("result => " + result);

        //获取自增长后的id值, 在Mybatis-Plus中自增长后的id值会回填到user对象中
        System.out.println("id => " + user.getId());
    }
}

运行结果:
在这里插入图片描述

可以看见,数据已经写入到了数据库,但是,id的值不正确,我们期望的是数据库自增长,实际是MP生成了id的值写入到了数据库。
在这里插入图片描述

1.3 设置Mybatis-Plus Id的生成策略

MP支持的id策略:

在这里插入图片描述

IdType.java

/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4),
	/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */ 
	/*** 全局唯一ID (idWorker) */
    @Deprecated
    ID_WORKER(3),
    /*** 字符串全局唯一ID (idWorker 的字符串表示) */
    @Deprecated
    ID_WORKER_STR(3),
	/*** 全局唯一ID (UUID) */
    @Deprecated
    UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

修改User对象,指定id类型为自增长
在这里插入图片描述

先把原来那条数据删除,然后我们把ID自增长设置为6,紧着上面那条数据:
在这里插入图片描述

然后重新运行程序:
在这里插入图片描述


1.4 @TableField

MyBtais-Plus中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个:

  1. 对象中的属性名和字段名不一致的问题(非驼峰,如果是驼峰命名法,Mybatis-Plus会自动帮你做转换,eg:userName 可以自动映射 user_name
  2. 对象中的属性字段在表中不存在的问题。
  3. 某些字段不加入查询(比如password)。

在这里插入图片描述在这里插入图片描述

效果:
在这里插入图片描述


2. 更新操作

Mybatis-Plus中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。


2.1 根据id更新

方法定义:


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

测试:

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestUserMapper {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testUpdateById() {
        User user = new User();
        user.setId(6L); // 主键
        user.setAge(21); // 更新的字段

        // 根据id更新, 更新不为null的字段
        this.userMapper.updateById(user);
    }
}

运行结果:

在这里插入图片描述


2.2 根据条件更新

说明,大多数时候,QueryWrapperUpdateWrapper是可以相互替换的。

方法定义:

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

在这里插入图片描述

Wrapper可以理解为查询条件。
在这里插入图片描述


2.2.1 QueryWrapper 用法

    @Test
    public void testUpdate() {
        User user = new User();
        user.setAge(2022); //更新的字段
        user.setPassword("8888888");

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", "zhangsan"); //匹配user_name = zhangsan 的用户数据

        //根据条件做更新
        int result = this.userMapper.update(user, wrapper);
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述


2.2.2 UpdateWrapper 用法

UpdateWrapper 更加倾向于链式调用

    @Test
    public void testUpdate2() {

        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.set("age", 21).set("password", "999999") //更新的字段
                .eq("user_name", "zhangsan"); //更新的条件

        //根据条件做更新
        int result = this.userMapper.update(null, wrapper);
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述


3. 删除操作


3.1 deleteById

方法定义:

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

具体示例:

    @Test
    public void testDeleteById() {
        // 删除id为1的数据
        int result = this.userMapper.deleteById(1L);
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述


3.2 deleteByMap

方法定义:

    /**
     * 根据 columnMap 条件,删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

具体示例:

    @Test
    public void testDeleteByMap() {
        Map<String, Object> map = new HashMap<>();
        // 删除的条件为 user_name为lisi, password为123456
        map.put("user_name", "lisi");
        map.put("password", "123456");

        // 根据map删除数据,多条件之间是and关系
        int result = this.userMapper.deleteByMap(map);
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述在这里插入图片描述


3.3 delete

方法定义:

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

测试:

删除usernamecaocao1password123456的用户。

    @Test
    public void testDelete() {
        //用法一: 注意, 这里QueryWrapper可以用updateWrapper替换
//        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.eq("user_name", "caocao1")
//                .eq("password", "123456");

        //用法二:
        User user = new User();
        user.setPassword("123456");
        user.setUserName("caocao1");

        QueryWrapper<User> wrapper = new QueryWrapper<>(user);
        // 根据包装条件做删除
        int result = this.userMapper.delete(wrapper);
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述在这里插入图片描述


3.4 deleteBatchIds

方法定义:

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

测试:

    @Test
    public void testDeleteBatchIds() {
        // 根据id批量删除数据
        int result = this.userMapper.deleteBatchIds(Arrays.asList(3L, 4L));
        System.out.println("result => " + result);
    }

运行结果:
在这里插入图片描述在这里插入图片描述


4. 查询操作(注意匹配的字段是数据库的字段,不是实体类的字段)

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

注意匹配的字段是数据库的字段,不是实体类的字段。假如数据库里面的字段是user_name,那么查询的时候应该eq(“user_name”,xxx),而不是q(“userName”,xxx)。


4.1 selectById

方法定义:

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

测试:

    @Test
    public void testSelectById() {
        // 查询id为5的用户
        User user = this.userMapper.selectById(5L);
        System.out.println(user);
    }

在这里插入图片描述


4.2 selectBatchIds

方法定义:

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

示例:

我们先给数据库多插入几条数据,前面的数据快被删完了,太惨了。

-- 插入测试数据
INSERT INTO `tb_user` ( `id`, `user_name`, `password`, `name`, `age`, `email` )
VALUES
	( '1', 'zhangsan', '123456', '张三', '18', 'test1@itcast.cn' );
INSERT INTO `tb_user` ( `id`, `user_name`, `password`, `name`, `age`, `email` )
VALUES
	( '2', 'lisi', '123456', '李四', '20', 'test2@itcast.cn' );
INSERT INTO `tb_user` ( `id`, `user_name`, `password`, `name`, `age`, `email` )
VALUES
	( '3', 'wangwu', '123456', '王五', '28', 'test3@itcast.cn' );
INSERT INTO `tb_user` ( `id`, `user_name`, `password`, `name`, `age`, `email` )
VALUES
	( '4', 'zhaoliu', '123456', '赵六', '21', 'test4@itcast.cn' );

在这里插入图片描述

下面编写测试代码:

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

运行结果:
在这里插入图片描述


4.3 selectOne

方法定义:

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

示例:

    @Test
    public void testSelectOne() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //查询条件
        wrapper.eq("password", "123456");
        // 查询的数据超过一条时, 会抛出异常
        User user = this.userMapper.selectOne(wrapper);
        System.out.println(user);
    }

运行结果:
在这里插入图片描述

我们改一下条件,只定位到一条数据。

    @Test
    public void testSelectOne() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //查询条件
        wrapper.eq("password", "123456").eq("id", 1);
        // 查询的数据超过一条时, 会抛出异常
        User user = this.userMapper.selectOne(wrapper);
        System.out.println(user);
    }

在这里插入图片描述


4.4 selectCount

方法定义:

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

示例:查询年龄大于20岁的用户数量

    @Test
    public void testSelectCount() {

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // gt是做大于的操作
        wrapper.gt("age", 20); // 条件:年龄大于20岁的用户

        // 根据条件查询数据条数
        Integer count = this.userMapper.selectCount(wrapper);
        System.out.println("count is : " + count);
    }

运行结果:
在这里插入图片描述

在这里插入图片描述


4.5 selectList

方法定义:

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

具体案例1:查询email字段包含itcast的用户

    @Test
    public void testSelectList() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //设置查询条件 这里设置的条件是email字段包含itcast这个值
        wrapper.like("email", "itcast");

        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

运行结果:
在这里插入图片描述

具体案例2:查询年龄大于23岁的用户

    @Test
    public void testSelectList() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //设置查询条件 这里设置的条件是年龄大于23岁
        wrapper.gt("age", 23);

        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

运行结果:
在这里插入图片描述


4.6 selectPage

方法定义:

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

配置分页插件:

在这里插入图片描述

MybatisPlusConfig.java

package com.tian.springbootmybatisplus;

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

@Configuration
@MapperScan("com.tian.mapper") //因为这个是配置类 所以我们把启动类的包扫描放在了这里
public class MybatisPlusConfig {
    @Bean //配置分页插件
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

编写测试用例:查询第一页, 查询3条数据(email包含itcast的数据)

    // 测试分页查询
    @Test
    public void testSelectPage() {

        Page<User> page = new Page<>(1, 3); //查询第一页, 查询3条数据

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //设置查询条件
        wrapper.like("email", "itcast");

        IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
        System.out.println("数据总条数: " + iPage.getTotal());
        System.out.println("数据总页数: " + iPage.getPages());
        System.out.println("当前页数: " + iPage.getCurrent());

        // 把拿到的数据打印出来
        List<User> records = iPage.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    }

运行结果:
在这里插入图片描述



本文含有隐藏内容,请 开通VIP 后查看