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

🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击
在这里插入图片描述在这里插入图片描述

一、 Mybatis-Plus是什么?

官方文档地址 :https://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表结构

idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com

创建表结构


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)
);

新增数据

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');

结果展示

在这里插入图片描述

3.2 新建Boot项目

引用spring boot starter 父工程

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/>
    </parent>

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

<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 数据库的相关配置:

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 文件夹:

@SpringBootApplication
@MapperScan("com.mapper")
public class Application {

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

}

3.4 新建对应实体类

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

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

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

}

3.5 测试

@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可见

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

sql可见
在这里插入图片描述

五、CRUD

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

// 插入一条记录
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接口

public interface UserDao extends BaseMapper<TestUser> {

}

5.2 Service – 业务逻辑层

继承IService接口

public interface UserService extends IService<User> {

}

5.3 实现类

继承ServiceImpl实现UserService 接口

@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 分页查询测试(有问题)

@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 增加分页拦截器配置(成功)

@Configuration
public class MpConfig {

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

在这里插入图片描述

7.3 Page对象

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

属性名类型默认值描述
recordsListemptyList查询数据列表
totalLong0查询列表总记录数
sizeLong10每页显示条数,默认 10
currentLong1当前页
ordersListemptyList排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本
optimizeCountSqlbooleantrue自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false
optimizeJoinOfCountSqlbooleantrue自动优化 COUNT SQL 是否把 join 查询部分移除
searchCountbooleantrue是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false
maxLimitLong单页分页条数限制
countIdStringxml 自定义 count 查询的 statementId

八、查询编写

8.1 条件查询的3种格式

8.1.1 第一种 (不推荐)

@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 表达式

@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(推荐)

@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的情况,所以要添加判断

表中数据
在这里插入图片描述

@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 查询部分属性


@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 查询未定义的属性


@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 表名映射

  • 描述:表名注解,标识当前实体类与数据库表的对应关系
  • 使用位置:实体类
@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

属性类型必须指定默认值描述
valueString“”数据库表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMapString“”xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludePropertyString[]{}需要排除的属性名 @since 3.3.1

9.2 @TableField 字段映射

  1. 设置当前对应数据库表中的字段关系
@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    @TableField("nickname")
    private String name;
    private Integer age;
    private String email;
}

  1. 数据库中未定义属性
@TableField(exist=false)
private Integer result;

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

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

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

注解属性如下:

属性类型必须指定默认值描述
valueString“”数据库字段名
existbooleantrue是否为数据库表字段
conditionString“”
updateString“”
insertStrategyEnumFieldStrategy.DEFAULT举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnumFieldStrategy.DEFAULT举例:IGNORED update table_a set column=#{columnProperty}
whereStrategyEnumFieldStrategy.DEFAULT举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
numericScaleString“”指定小数点后保留的位数

9.3 @TableId 主键类型

  • 描述:主键注解
  • 使用位置:实体类主键字段
@TableName("sys_user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

属性类型必须指定默认值描述
valueString“”主键字段名
typeEnumIdType.NONE指定主键类型

IdType

描述
AUTO数据库 ID 自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert 前自行 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)
UUID32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

9.1 @Version 乐观锁

  1. 第一步 :表中增加乐观锁标记
    在这里插入图片描述2. 实体类中添加对应字段
@Data
public class User {
 
    @Version
    private Integer version;
}

  1. 配置乐观锁拦截器
@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 逻辑删除

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

或者配置文件全局配置

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

十、全局配置

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

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

但是

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

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream_sky分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值