MyBatis-Plus精讲和使用注意事项

🍓 简介:java系列技术分享(👉持续更新中...🔥)

🍓 初衷:一起学习、一起进步、坚持不懈

🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏

🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

一、 Mybatis-Plus是什么?

官方文档地址:www.baomidou.com/

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增

强不做改变,为简化开发、提高效率而生。

MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

二、Mybatis和Mybatis-Plus区别

MyBatis:

  1. 所有SQL语句全部自己写
  2. 手动解析实体关系映射转换为MyBatis内部对象注入容器
  3. 不支持Lambda形式调用
  4. 驼峰(属性)和下划线(字段)的映射关系 mybatis中默认是关闭的。

Mybatis Plus:

  1. 强大的条件构造器,满足各类使用需求
  2. 内置的Mapper,通用的Service,少量配置即可实现单表大部分CRUD操作
  3. 支持Lambda形式调用
  4. 提供了基本的CRUD功能,连SQL语句都不需要编写
  5. 自动解析实体关系映射转换为MyBatis内部对象注入容器
  6. 驼峰(属性)和下划线(字段)的映射关系Mybatis-Plus中 默认是开启的 ,不需要额外配置。

三、快速入门

我们将通过一个简单的 Demo 来阐述 MyBatis-Plus 的强大功能

3.1 创建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

创建表结构

sql 复制代码
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)
);

新增数据

sql 复制代码
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');

结果展示

![在这里插入图片描述](img-blog.csdnimg.cn/07e67c759a6... =900x300)

3.2 新建Boot项目

引用spring boot starter 父工程

xml 复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/>
    </parent>

引入对应依赖这里使用mysql数据库

xml 复制代码
<dependencies>
    <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>3.5.1</version>
    </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
                <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.11</version>
        </dependency>
         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
</dependencies>

3.3 添加配置

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

yaml 复制代码
spring:
  # 数据源配置
  datasource:
      # 数据库连接信息配置
     datasource:
       type: com.alibaba.druid.pool.DruidDataSource
       driver-class-name: com.mysql.cj.jdbc.Driver
       url: jdbc:mysql:///test_demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true&failOverReadOnly=false
       username: root
       password: root

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

java 复制代码
@SpringBootApplication
@MapperScan("com.mapper")
public class Application {

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

}

3.4 新建对应实体类

java 复制代码
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

编写 Mapper 包下的 UserMapper接口 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能

java 复制代码
//@Mapper  没有没配@MapperScan的需添加@Mapper注解
public interface UserMapper extends BaseMapper<User> {

}

3.5 测试

java 复制代码
@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);
    }
}

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

3.6 控制台输出

四、开启日志SQL可见

yaml 复制代码
mybatis-plus:
  configuration:
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

sql可见

五、CRUD

方法非常多,我简单列出几个,具体请查看官方文档中的接口链接:接口文档

java 复制代码
// 插入一条记录
int insert(T entity);

// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);


// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);


// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

5.1 Mapper-数据操作层

继承BaseMapper接口

java 复制代码
public interface UserDao extends BaseMapper<TestUser> {

}

5.2 Service -- 业务逻辑层

继承IService接口

java 复制代码
public interface UserService extends IService<User> {

}

5.3 实现类

继承ServiceImpl实现UserService 接口

java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

}

六、条件构造器Wrapper

条件构造文档链接

AbstractWrapper QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类

用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件

注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

七、分页插件

7.1 分页查询测试(有问题)

java 复制代码
@SpringBootTest
public class TestPlus {
    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectPage(){
        Page<User> page = new Page<>(1,2);
        Page<User> result = userMapper.selectPage(page, null);
        System.out.println("当前页码"+result.getCurrent());
        System.out.println("每页数量"+result.getSize());
        System.out.println("数据总数"+result.getTotal());
        System.out.println("当前页数据"+result.getRecords());
    }
}

发现分页未生效

7.2 增加分页拦截器配置(成功)

java 复制代码
@Configuration
public class MpConfig {

    @Bean
    public MybatisPlusInterceptor pageInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

7.3 Page对象

该类继承了 IPage 类,实现了 简单分页模型 如果你要实现自己的分页模型可以继承 Page 类或者实现 IPage 类

属性名 类型 默认值 描述
records List emptyList ==查询数据列表==
total Long 0 查询列表总记录数
size Long 10 每页显示条数,默认 10
current Long 1 当前页
orders List emptyList 排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本
optimizeCountSql boolean true 自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false
optimizeJoinOfCountSql boolean true 自动优化 COUNT SQL 是否把 join 查询部分移除
searchCount boolean true 是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false
maxLimit Long 单页分页条数限制
countId String xml 自定义 count 查询的 statementId

八、查询编写

8.1 条件查询的3种格式

8.1.1 第一种 (不推荐)

java 复制代码
@SpringBootTest
public class TestPlus {
    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectPage(){
        //查询年龄大于5岁小于20岁的用户
        //构造条件
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.lt("age",20);
        qw.gt("age",5);
        List<User> userList = userMapper.selectList(qw);
        System.out.println(userList);
    }
}

结果成功 缺点:字段名容易写错

8.1.2 第二种 Lambda 表达式

java 复制代码
@SpringBootTest
public class TestPlus {
    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectPage(){
        //查询年龄大于5岁小于20岁的用户
        //构造条件
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.lambda().lt(User::getAge,20).gt(User::getAge,5);
        List<User> userList = userMapper.selectList(qw);
        System.out.println(userList);
    }
}

结果成功,但是每次都需要.lambda()

8.1.3 第三种 直接使用LambdaQueryWrapper(推荐)

java 复制代码
@SpringBootTest
public class TestPlus {
    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectPage(){
     //查询年龄大于5岁小于20岁的用户
        //构造条件
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        qw.lt(User::getAge,20).gt(User::getAge,5);
        List<User> userList = userMapper.selectList(lqw);
        System.out.println(userList);
    }
}

8.2 查询条件null值处理

由于存在请求参数可能有值或者null的情况,所以要添加判断

表中数据

java 复制代码
@SpringBootTest
public class TestPlus {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectNotNull(){
        //模拟查询条件
        UserDTO userDTO = new UserDTO();
        userDTO.setAge(5);
        userDTO.setAge2(20);
        //构造条件
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //链式编程,分开也可以
		    lqw.ge(null!=userDTO.getAge(),User::getAge,userDTO.getAge())
		       .lt(null!=userDTO.getAge2(),User::getAge,userDTO.getAge2());
        List<User> userList = userMapper.selectList(lqw);
        System.out.println(userList);
    }
}

结果

8.3 查询部分属性

java 复制代码
@SpringBootTest
public class TestPlus {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectPortion(){
        //构造条件
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.select(User::getId,User::getName);
        List<User> userList = userMapper.selectList(lqw);
        System.out.println(userList);
    }
}

8.4 查询未定义的属性

java 复制代码
@SpringBootTest
public class TestPlus {

    @Autowired
    private UserMapper userMapper;
    
    @Test
    void testSelectPortion2(){
        //构造条件
        QueryWrapper<User> lqw = new QueryWrapper<>();
        lqw.select("count(1) num,age");
        lqw.groupBy("age");
        List<Map<String, Object>> maps = userMapper.selectMaps(lqw);
        System.out.println(maps);
    }
}

并且别名也能生效

九、常用注解使用(配置映射关系)

9.1 @TableName 表名映射

  • 描述:表名注解,标识当前实体类与数据库表的对应关系
  • 使用位置:实体类
java 复制代码
@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性 类型 必须指定 默认值 描述
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

9.2 @TableField 字段映射

  1. 设置当前对应数据库表中的字段关系
java 复制代码
@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    @TableField("nickname")
    private String name;
    private Integer age;
    private String email;
}
  1. 数据库中未定义属性
java 复制代码
@TableField(exist=false)
private Integer result;

exist:设置属性在数据库表字段中是否存在,默认为true.此属性无法与value合并使用

  1. 密码不想被查询
java 复制代码
@TableField(value = "pwd",select = false)
private String password;

select:设置属性是否参与查询,此属性与select()映射配置不冲突

注解属性如下:

属性 类型 必须指定 默认值 描述
value String "" 数据库字段名
exist boolean true 是否为数据库表字段
condition String ""
update String ""
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 Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
numericScale String "" 指定小数点后保留的位数

9.3 @TableId 主键类型

  • 描述:主键注解
  • 使用位置:实体类主键字段
java 复制代码
@TableName("sys_user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性 类型 必须指定 默认值 描述
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)

9.1 @Version 乐观锁

  1. 第一步 :表中增加乐观锁标记 2. 实体类中添加对应字段
java 复制代码
@Data
public class User {
 
    @Version
    private Integer version;
}
  1. 配置乐观锁拦截器
java 复制代码
@Configuration
public class MpConfig {

    @Bean
    public MybatisPlusInterceptor pageInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //分页插件
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //乐观锁
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}
  1. 使用乐观锁在修改前必须先获取对应version字段数据
  2. 原理 update user set age = 12 ,version = version +1 where version = ? ? 查询出来的version结果

9.1 @TableLogic 逻辑删除

java 复制代码
public class User{
	@TableLogic(value = "0",delval = "1")
	private Integer isDelete;
}

或者配置文件全局配置

yaml 复制代码
mybatis-plus:
 global-config:
   db-config:
     logic-delete-field: isDelete
     #逻辑未删除值
     logic-not-delete-value: 0
     #逻辑已删除值
     logic-delete-value: 1

十、全局配置

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      #id类型
      id-type: ASSIGN_ID
      #数据库表默认前缀
      table-prefix: tb_

本篇持续更新...........

相关推荐
喵叔哟5 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟5 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk8 分钟前
maven环境搭建
java·maven
Daniel 大东27 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
wind瑞33 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen33 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)39 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿39 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
修道-032340 分钟前
【JAVA】二、设计模式之策略模式
java·设计模式·策略模式
九圣残炎1 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode