一.基础内容

1.1MyBatis Plus是国产的工具,IDEA不支持

MyBatis Plus是国产的工具,IDEA不支持,我们要手动导包。MyBatis Plus是包含了MyBatis的,所以,我们创建项目的时候,不要勾选MyBatis否则,会导致jar包冲突,引发错误。

1.2引入依赖

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

1.3BaseMapper提供的方法

1.3.1code

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.baomidou.mybatisplus.core.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.exceptions.TooManyResultsException;

public interface BaseMapper<T> extends Mapper<T> {
    int insert(T entity);

    int deleteById(Serializable id);

    int deleteById(T entity);

    default int deleteByMap(Map<String, Object> columnMap) {
        QueryWrapper<T> qw = Wrappers.query();
        return this.delete((Wrapper)qw.allEq(columnMap));
    }

    int delete(@Param("ew") Wrapper<T> queryWrapper);

    int deleteBatchIds(@Param("coll") Collection<?> idList);

    int updateById(@Param("et") T entity);

    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

    T selectById(Serializable id);

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    default List<T> selectByMap(Map<String, Object> columnMap) {
        QueryWrapper<T> qw = Wrappers.query();
        return this.selectList((Wrapper)qw.allEq(columnMap));
    }

    default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
        return (T)this.selectOne(queryWrapper, true);
    }

    default T selectOne(@Param("ew") Wrapper<T> queryWrapper, boolean throwEx) {
        List<T> list = this.selectList(queryWrapper);
        int size = list.size();
        if (size == 1) {
            return (T)list.get(0);
        } else if (size > 1) {
            if (throwEx) {
                throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
            } else {
                return (T)list.get(0);
            }
        } else {
            return null;
        }
    }

    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0L;
    }

    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);

    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

    List<Map<String, Object>> selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper);

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

    default <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
        List<T> list = this.selectList(page, queryWrapper);
        page.setRecords(list);
        return page;
    }

    default <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
        List<Map<String, Object>> list = this.selectMaps(page, queryWrapper);
        page.setRecords(list);
        return page;
    }
}

1.3.2方法解释

  1. insert(T entity)
    • 作用:新增单条老虎数据

    • 参数:entity 为待新增的 Tiger 对象,需封装 tigerName/tigerAge/tigerSalary 等字段值

    • 特点:自动生成插入 SQL,支持 tiger_id 主键自增(需实体类 @TableId 配置 type=AUTO)

    • 示例:

      Tiger tiger = new Tiger();
      tiger.setTigerName("孙虎");
      tiger.setTigerAge(2);
      tiger.setTigerSalary(300.50);
      tigerMapper.insert(tiger); // 插入后自动回填tiger_id
  2. deleteById(Serializable id)
    • 作用:根据老虎 ID(主键)删除单条数据

    • 参数:id 为 tiger_id 值(Integer 类型,需与实体类主键类型一致)

    • 特点:仅支持主键删除,无需编写 delete SQL

    • 示例:

      tigerMapper.deleteById(1); // 删除tiger_id=1的老虎数据
  3. deleteByMap(Map<String, Object> columnMap)
    • 作用:按多字段等值匹配删除老虎数据

    • 参数:columnMap 的 key 为数据库字段名(如 tiger_name),value 为匹配值

    • 特点:仅支持等值条件,不支持模糊、范围等复杂条件

    • 示例:

      Map<String, Object> map = new HashMap<>();
      map.put("tiger_name", "李虎"); // 数据库字段名
      map.put("tiger_age", 3);
      tigerMapper.deleteByMap(map); // 删除名称为李虎且年龄为3的老虎
  4. updateById(T entity)
    • 作用:根据老虎 ID(主键)更新数据

    • 参数:entity 需封装 tiger_id(主键)和待更新的字段值(非 null 字段才会更新)

    • 特点:自动定位主键对应的记录,仅更新非 null 字段

    • 示例:

      Tiger tiger = new Tiger();
      tiger.setTigerId(1); // 必须指定主键
      tiger.setTigerSalary(600.00); // 仅更新薪资字段
      tigerMapper.updateById(tiger);
  5. update(T entity, Wrapper<T> updateWrapper)
    • 作用:按条件更新老虎数据

    • 参数:entity 封装待更新字段值,updateWrapper 封装更新条件(如模糊、范围)

    • 特点:支持复杂更新条件,避免手动拼接 SQL

    • 示例:

      Tiger tiger = new Tiger();
      tiger.setTigerSalary(800.00); // 待更新的薪资
      // 条件:年龄大于5的老虎
      UpdateWrapper<Tiger> wrapper = new UpdateWrapper<>();
      wrapper.gt("tiger_age", 5);
      tigerMapper.update(tiger, wrapper);
  6. selectById(Serializable id)
    • 作用:根据老虎 ID(主键)查询单条数据

    • 参数:id 为 tiger_id 值(Integer 类型)

    • 返回值:匹配的 Tiger 对象,无数据则返回 null

    • 示例:

      Tiger tiger = tigerMapper.selectById(1); // 查询tiger_id=1的老虎
  7. selectList(Wrapper<T> queryWrapper)
    • 作用:按条件查询多条老虎数据

    • 参数:queryWrapper 为查询条件封装器(传 null 则查询全表)

    • 返回值:匹配的 Tiger 对象列表,支持等值、模糊、排序等多类条件

    • 示例:

      // 无条件查询全表
      List<Tiger> list = tigerMapper.selectList(null);
      // 带条件:薪资大于200的老虎,按年龄降序
      QueryWrapper<Tiger> wrapper = new QueryWrapper<>();
      wrapper.gt("tiger_salary", 200).orderByDesc("tiger_age");
      List<Tiger> list2 = tigerMapper.selectList(wrapper);
核心说明
  • deleteById/selectById的参数类型为 Integer(匹配 Tiger 实体的 tigerId 类型),需与 t_tiger 表的 tiger_id(INT 类型)一致;

  • deleteByMap的 key 必须是数据库字段名(如 tiger_name),而非实体类属性名(tigerName);

  • 所有方法无需手动编写 XML 或注解 SQL,MyBatis-Plus 自动生成适配 t_tiger 表的 SQL。

1.4 IService<T>接口和ServiceImpl实现类

1.4.1语法

1.4.2ServiceImpl核心方法

  1. save(T entity)
    • 作用:新增单条老虎数据(底层调用 BaseMapper.insert)

    • 参数:entity 为待新增的 Tiger 对象

    • 特点:方法名贴合业务语义,与 Mapper 层 insert 做区分

    • 示例:

      Tiger tiger = new Tiger();
      tiger.setTigerName("周虎");
      tiger.setTigerAge(4);
      tiger.setTigerSalary(700.00);
      tigerService.save(tiger);
  2. removeById(Serializable id)
    • 作用:根据老虎 ID 删除单条数据(底层调用 BaseMapper.deleteById)

    • 参数:id 为 tiger_id 值(Integer 类型)

    • 特点:方法名用 remove,更符合业务层 “删除” 语义

    • 示例:

      tigerService.removeById(2); // 删除tiger_id=2的老虎
  3. removeByMap(Map<String, Object> columnMap)
    • 作用:按多字段等值匹配删除老虎数据(底层调用 BaseMapper.deleteByMap)

    • 参数:columnMap 的 key 为数据库字段名(如 tiger_age),value 为匹配值

    • 示例:

      Map<String, Object> map = new HashMap<>();
      map.put("tiger_age", 7);
      tigerService.removeByMap(map); // 删除年龄为7的老虎
  4. updateById(T entity)
    • 作用:根据老虎 ID 更新数据(底层调用 BaseMapper.updateById)

    • 参数:entity 需封装 tiger_id 和待更新字段值

    • 示例:

      Tiger tiger = new Tiger();
      tiger.setTigerId(3);
      tiger.setTigerName("张虎-更新");
      tigerService.updateById(tiger);
  5. updateBatchById(Collection<T> entityList):可以多一个参数指定更新多少参数
    • 作用:按主键批量更新老虎数据

    • 参数:entityList 为待更新的 Tiger 对象集合

    • 特点:底层分批执行 updateById,默认批次大小 1000,可自定义

    • 示例:

      List<Tiger> list = new ArrayList<>();
      // 第一条更新数据
      Tiger t1 = new Tiger();
      t1.setTigerId(1);
      t1.setTigerSalary(550.00);
      // 第二条更新数据
      Tiger t2 = new Tiger();
      t2.setTigerId(2);
      t2.setTigerSalary(850.00);
      list.add(t1);
      list.add(t2);
      tigerService.updateBatchById(list); // 批量更新
      // 自定义批次大小(如500)
      // tigerService.updateBatchById(list, 500);
  6. getById(Serializable id)
    • 作用:根据老虎 ID 查询单条数据(底层调用 BaseMapper.selectById)

    • 参数:id 为 tiger_id 值(Integer 类型)

    • 返回值:匹配的 Tiger 对象,无数据则返回 null

    • 特点:方法名用 get,贴合业务层 “查询单行” 语义

    • 示例:

      Tiger tiger = tigerService.getById(3); // 查询tiger_id=3的老虎
  7. list(Wrapper<T> queryWrapper):Lambda查询
    • 作用:按条件查询多条老虎数据(底层调用 BaseMapper.selectList)

    • 参数:queryWrapper 为查询条件封装器(传 null 则查询全表),支持 LambdaQueryWrapper 避免硬编码字段名

    • 返回值:匹配的 Tiger 对象列表

    • 示例:

      // 无条件查询全表
      List<Tiger> allTigers = tigerService.list(null);
      // Lambda条件:薪资大于500且年龄小于6的老虎
      LambdaQueryWrapper<Tiger> lambdaWrapper = new LambdaQueryWrapper<>();
      lambdaWrapper.gt(Tiger::getTigerSalary, 500).lt(Tiger::getTigerAge, 6);
      List<Tiger> list = tigerService.list(lambdaWrapper);
  8. page(IPage<T> page, Wrapper<T> queryWrapper):分页查询
    • 作用:分页查询老虎数据

    • 参数:page 指定分页参数(页码、页大小),queryWrapper 为查询条件

    • 返回值:IPage 对象(含当前页数据、总条数、总页数等分页信息)

    • 特点:补充 Mapper 层缺失的分页能力,适配业务层分页需求

    • 示例:

      // 分页参数:第1页,每页3条
      IPage<Tiger> page = new Page<>(1, 3);
      // 条件:薪资大于200
      QueryWrapper<Tiger> wrapper = new QueryWrapper<>();
      wrapper.gt("tiger_salary", 200);
      // 分页查询
      IPage<Tiger> tigerPage = tigerService.page(page, wrapper);
      // 获取分页结果
      System.out.println("总条数:" + tigerPage.getTotal());
      System.out.println("总页数:" + tigerPage.getPages());
      System.out.println("当前页数据:" + tigerPage.getRecords());

1.5Mapper类和LambdaWrapper

【MyBatis Plus】Wrapper接口-CSDN博客

1.6动态条件控制(基于Wrapper)

// 动态参数(可能为null)
String tigerName = "虎"; 
Integer minSalary = 300;

LambdaQueryWrapper<Tiger> wrapper = Wrappers.lambdaQuery();
// 仅当tigerName非null时,拼接“tiger_name LIKE '%虎%'”
wrapper.like(tigerName != null, Tiger::getTigerName, tigerName);
// 仅当minSalary非null时,拼接“tiger_salary > 300”
wrapper.gt(minSalary != null, Tiger::getTigerSalary, minSalary);

1.7条件优先级控制

1.7.1举例

通过 and()/or()nested() 控制条件分组,避免条件优先级错误:

wrapper.nested(w -> w.gt(Tiger::getTigerAge, 3).gt(Tiger::getTigerSalary, 500))
       .or()
       .eq(Tiger::getTigerName, "王虎");

1.7.2生成的SQL

(tiger_age > 3 AND tiger_salary > 500) OR tiger_name = '王虎'

1.7.3nested内部类 - 简写Lambda的nested

1.8逻辑删除和物理删除

1.8.1区分逻辑删除和物理删除

逻辑删除是 MyBatis-Plus 提供的 “假删除” 能力:不物理删除数据库记录,仅修改指定字段的状态标记(如deleted=1),保留数据便于恢复和分析,区别于直接删除数据的 “物理删除”。

  • 物理删除:真实删除,将 t_tiger 表中对应记录从数据库中移除,后续无法查询;

  • 逻辑删除:假删除,将 t_tiger 表中代表 “是否删除” 的字段改为 “已删除状态”,记录仍保存在数据库中,查询时自动过滤已删除数据。(MyBatis Plus 的「逻辑删除」核心就是只标记、不物理删除—— 数据库里的记录永远不会被真正删除,只是通过一个 “删除标记字段”

        (比如 deleted)标记为 “已删除”,且 MP 会自动帮你处理 CRUD 时的条件过滤,即使是CRUD也是不会在数据库中删除这个记录)

增加delete字段

1.8.2@TableLogic标签(@TableLogic 是 MyBatis Plus 专门用于标记逻辑删除字段的注解,它是实现 “只标记、不物理删除” 的核心注解)

@TableLogic 的核心是:告诉 MyBatis Plus “这个字段是逻辑删除标记字段”,让 MP 自动完成两件事:

  1. 删除操作:调用 deleteById/remove 时,自动把 DELETE 语句转为 UPDATE 语句(更新标记字段);

    2.查询 / 更新操作:自动给 SQL 拼接 WHERE 逻辑删除字段=未删除值,过滤已标记删除的记录。

1.8.3配置全局逻辑删除规则,适配 t_tiger 表及其他表的逻辑删除字段

#配置全局逻辑删除规则,适配 t_tiger 表及其他表的逻辑删除字段
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 逻辑删除字段的实体类属性名(此处为deleted)
      logic-delete-value: 1       # 逻辑已删除值(默认为1,对应t_tiger表的deleted=1)
      logic-not-delete-value: 0   # 逻辑未删除值(默认为0,对应t_tiger表的deleted=0)

1.8.4对应关系

entities中的类的删除字段按java命名风格,配置文件,数据库字段的名字按照数据库的下划线命名。

1.8.5案例展示(逻辑上删除了,但是数据库中的记录还在)

二.标签

2.1@TableName :指定数据库表名

2.2@TableId(value="",type=IdType.AUTO )  :  指定主键字段和类型

2.2.1语法格式

        专用于标记实体类中的主键属性,绑定数据库表的主键字段,同时指定主键的生成策略(如自增、UUID 等)。

2.2.2value字段:声明主键对应的数据库字段名

属性名 类型 必选 说明
value String 声明主键对应的数据库字段名(默认值:属性名转下划线,如tigerIdtiger_id

2.2.3type字段:主键生成策略

属性名 类型 必选 说明
type IdType 主键生成策略(默认值:跟随全局配置,常用AUTO/ASSIGN_ID/INPUT
策略值 含义 适用场景
AUTO 数据库自增(依赖表的主键自增配置) 如 t_tiger 表的 tiger_id(INT AUTO_INCREMENT)
ASSIGN_ID MP 自动生成雪花算法 ID(Long 类型) 分布式系统、无需数据库自增的主键
ASSIGN_UUID MP 自动生成 UUID(String 类型,无中划线) 字符串类型主键、需全局唯一
INPUT
* /**
 * 登录表现层:加@RestController(已保留),通过@Autowired注入Service(移除手动new)
 * 仅处理请求、参数校验、调用Service、操作Session、返回响应
 */
@RestController
@RequestMapping("auth")
public class LoginController {

    // 核心改造:移除手动new,通过@Autowired从容器注入UserService
    @Autowired
    private UserService userService;

    /**
     * 登录接口
     * /auth/login post方式 请求体传递参数 username password
     * 验证成功以后,将账号存储在session!
     * 返回 {code:200,message:"登录成功",data:null}
     */
    @PostMapping("login")
    public Result login(HttpSession session, @Valid @RequestBody SysUserLoginDto user, BindingResult bindingResult) {
        // 1. 表现层职责:仅做参数格式校验(无业务逻辑)
        if (bindingResult.hasErrors()) {
            return Result.fail(500, "账号和密码不符合规则,登录失败!");
        }
        // 2. 调用Service完成登录业务校验(不直接调用工具类/DAO)
        boolean logined = userService.login(user.getUsername(), user.getPassword());
        if (!logined) {
            return Result.fail("账号或者密码错误!");
        }
        // 3. 表现层职责:操作Session(属于请求响应层面,无需走Service)
        session.setAttribute("username", user.getUsername());
        return Result.success("登录成功!");
    }

    /**
     * 退出登录接口
     * /auth/logout get方式 没有参数
     * 清空session数据,返回成功响应
     * 返回 {code:200,message:"退出登录成功",data:null}
     */
    @GetMapping("logout")
    public Result logout(HttpSession session) {
        // 表现层职责:操作Session(无需走Service/DAO)
        session.removeAttribute("username");
        session.invalidate();
        return Result.success("退出登录成功!");
    }
}
主键非自增、需业务自定义赋值
NONE 无策略(跟随全局配置) 沿用项目全局主键策略

2.2.4全局配置主键自增

# 全局配置主键自增
mybatis-plus.global-config.db-config.id-type=auto

 2.2.5配置文件统一指定表的名称前缀

mybatis-plus.global-config.db-config.table-prefix=t_

2.3@TableField  :  匹配表的字段

2.3.1语法格式

        专用于标记实体类中的非主键属性,绑定数据库表的普通字段,解决 “属性名与字段名不一致、字段是否参与 CRUD” 等问题。

2.3.2字段汇总

属性名 类型 必选 说明
value String 声明属性对应的数据库字段名(默认值:属性名转下划线,如tigerNametiger_name)【绑定这种普通的匹配,比如:t_id 匹配 tID的时候,value可以省略】
exist boolean 标记属性是否对应数据库字段(true:存在;false:仅实体类属性,无对应字段)
fill FieldFill 字段自动填充策略(如创建时间、修改时间自动赋值)
select boolean 标记字段是否参与查询(true:参与;false:查询时忽略该字段)

2.4@Configuration+@Bean标签声明Bean对象

2.4.1怎么理解POJO生命周期和Bean生命周期的区别(我的理解)

       我可以理解为,类似于工具,需要被从Spring项目启动到结束,被很多服务调用的,如果是组件,就加@Component以及子标签的组件标签,如果是别的第三方的工具等(比如 Redis、线程池),就加@Configuration和@Bean

2.4.2使用@Configuration+@Bean生命和管理Druid数据库

@Configuration
@PropertySource("classpath:config/jdbc.properties")
public class Demo15Config {

    // 省略配置参数注入的属性...

    /**
     * 创建Druid数据源Bean,纳入IoC容器管理
     * @Bean("myDruidDataSource"):自定义Bean的ID为myDruidDataSource(默认是方法名getDruidDataSource)
     * @Scope("prototype"):设置为多实例(默认单例,开发中极少用多实例)
     * @return DruidDataSource对象(IoC容器会缓存该对象)
     */
    @Bean("myDruidDataSource")
    // @Scope("prototype") // 如需多实例则打开注释,默认单例无需配置
    public DataSource getDruidDataSource() {
        // 手动创建Druid数据源对象(第三方类,无法加@Component注解)
        DruidDataSource druidDataSource = new DruidDataSource();
        // 设置数据库连接参数(从配置文件注入的属性)
        druidDataSource.setUsername(userName);
        druidDataSource.setPassword(password);
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClassName);
        // 返回对象:Spring会自动将该对象存入IoC容器
        return druidDataSource;
    }
}

2.5IPage分页

2.5.1声明MybatisPlusInterceptor拦截器作为Bean(可复用-注意更改DbType.为自己数据库产品名)

@Configuration
public class MPConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 核心:添加分页插件,指定数据库类型为MySQL(适配t_tiger表)
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐