1. mybatisplus概述

官方文档:链接
mybatisplus是一个mybatis的增强工具,在mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。

1.1 特性

在这里插入图片描述

1.2 快速入门

1.先建个数据库mybatisplus,然后执行下面代码建表

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

然后建个springboot项目
2.导入对应的依赖:

<!--MySQL驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <!-- 可通过version设置版本号 -->
</dependency>

<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!-- mybatisplus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

说明:使用 mybatisplus 可以节省我们大量的代码,但尽量不要同时导入mybatis 和 mybatisplus!会有版本的差异!

3.连接数据库,与mybatis一样

# 数据库8.版本需要加上cj
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

4.编写测试
传统编写方式: pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller
使用了mybatisplus之后:

  • pojo
    在这里插入图片描述

  • mapper接口
    在这里插入图片描述
    User代表对应的实体类,实体类对应到数据库表名!
    不要忘记在主启动类上扫描我们的mapper包下的所有接口:

    @MapperScan("com.liu.mapper") //扫描mapper文件夹
    
  • 使用
    在这里插入图片描述

1.3 配置日志

我们所有的sql现在不可见的,因此若想知道它是怎么执行的必须要看日志!
在核心配置文件中:

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

配置完毕日志之后,后面的学习就需要注意这个自动生成得SQL
在这里插入图片描述

1.4 CRUD扩展

1.4.1 insert插入

在这里插入图片描述
数据库插入的id的默认值:全局的唯一id

1.4.2 主键生成策略

在这里插入图片描述
雪花算法生成的id几乎可以保证全球唯一

这里先说三个注解:都是当与数据库中的名字不能按照驼峰对应上时需要用。

@TableName(value=“”):映射数据库表名
@TableId(value=“”):映射数据库表主键
@TableField(value=“”):映射数据库表非主键属性

通过注解的方式可设置生成的id。
在这里插入图片描述
下面是几种方式:

  • ID_WORKER:全局唯一ID(默认)
  • AUTO:主键递增
    • 需要在实体类字段上配置@TableId(type = IdType.AUTO)
    • 数据库字段一定要是递增的
      在这里插入图片描述
    • 再次进行插入操作发现id号比原来加1,现在是递增的!
      在这里插入图片描述
  • INPUT:手动输入id
    在实体类字段上配置:@TableId(type = IdType.INPUT)
    在这里插入图片描述
  • 其余的取值解释
    在这里插入图片描述

1.4.3 更新操作

在这里插入图片描述
所有的sql都是自动帮你动态配置的!

1.4.4 自动填充

创建时间、修改时间 这些操作一般都是自动化完成的,不需要手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!

  1. 在数据库中user表添加两个属性 create_time 和 update_time

  2. 然后在实体类字段属性上添加注解
    在这里插入图片描述

  3. 编写处理器来处理这个注解
    在这里插入图片描述

  4. 测试插入、观察时间
    在这里插入图片描述

  5. 测试更新、观察时间
    在这里插入图片描述

1.4.5 乐观锁

乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再更新值测试。
悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论干什么都会上锁,然后再去操作!

乐观锁实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败
    在这里插入图片描述

实现过程:

  • 在数据库中加入version属性,先全赋值为1

  • 在实体类version字段添加注解
    在这里插入图片描述

  • 编写配置类
    在这里插入图片描述
    这里要注意,采用了新版的乐观锁插件,需要添加依赖:

     <!-- 新版乐观锁依赖 -->
     <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-generator</artifactId>
         <version>3.4.0</version>
     </dependency>
    
  • 测试
    首先是单线程,一定能修改成功!
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
然后是多线程,前者修改失败!
在这里插入图片描述
在这里插入图片描述
最后更新是222,没有让111覆盖掉!

1.4.6 查询操作

测试批量查询:
在这里插入图片描述
测试条件查询:
在这里插入图片描述

1.4.7 分页查询

首先在配置类中配置分页插件
在这里插入图片描述
然后直接使用Page对象即可
在这里插入图片描述

1.4.8 删除操作

普通删除
在这里插入图片描述
批量删除
在这里插入图片描述
通过map条件删除
在这里插入图片描述

1.4.9 逻辑删除

物理删除:从数据库直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效!deleted=0 => deleted=1
管理员可以查看被删除的记录,用户删除时应用的就是逻辑删除。用于防止数据的丢失,类似于回收站。
1、在数据库表中增加一个字段deleted(注意不能为delete),默认为0
2、实体类中增加属性
在这里插入图片描述
3、在核心配置文件中配置
在这里插入图片描述
4、测试使用
执行删除操作
在这里插入图片描述
然后我们再执行查询操作发现查询条件自动判断deleted。已查询不到数据
在这里插入图片描述

1.4.10 性能分析插件

1、先导入依赖

<!-- 新版性能分析依赖 -->
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>

2、然后修改核心配置文件

#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
# 上面是原先的配置,更改为下方的新版性能分析的配置
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8

3、新建spy.properties配置文件,并编写内容

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

4、测试
在这里插入图片描述

1.4.11 条件构造器Wrapper

1.4.11.1 查询

方式一:new QueryWrapper 或者 new LambdaQueryWrapper

带上Lambda是方便书写查询条件时用lambda表达式。
这种条件适合于查询条件不是一下写完的,经过一些判断分开写的。

QueryWrapper<实体> wrapper = new QueryWrapper<>();
wrapper.lambda().eq()....  // 加lambda()是后面方便使用lambda表达式,比如 .eq(User::getUserId, "")

测试一:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试二:
在这里插入图片描述
测试三(between查询):
在这里插入图片描述
测试四(模糊查询):
在这里插入图片描述
测试五(子查询):
在这里插入图片描述
测试六(排序):
在这里插入图片描述
方式二:Wrappers.<实体>lambdaQuery()用法(推荐)
(这种方式更简洁,适合于一次性将所有条件写完)
还可以 Wrappers.lambdaQuery(实体.class) ,一样的。

sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
             .eq(SysUser::getAccount, username)
             .eq(SysUser::getMobile, mobile));

sql语句为:

select * from sys_user where account = #{username} and mobile = #{mobile};
1.4.11.2 更新

同查询,也是两种方式。
方式一:

在这里插入图片描述

方式二:

Wrappers.lambdaUpdate <实体.class> 用法
在这里插入图片描述

1.4.11.3 删除

wrapper 与查询时类似。

在这里插入图片描述

1.4.12 代码自动生成器(下面有通过MybatisCodeHelperPro插件实现的,更简单)

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
1、设置配置类
在这里插入图片描述
2、设置核心配置文件,还有用于性能分析的spy.properties(可选)。

# 数据库连接配置
# 数据库8.版本需要加上cj
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
# 新版性能分析的配置
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8

spring.datasource.username=root
spring.datasource.password=root

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# 逻辑删除,逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0

3、新建一个类,这里是在测试文件夹下建的类:

package com.liu;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
//代码自动生成器
public class LiuCode {
    public static void main(String[] args) {
        //我们需要构建一个代码生成器对象
        AutoGenerator mpg = new AutoGenerator();
        //怎么样去执行,配置策略
        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");//获取当前目录
        gc.setOutputDir(projectPath+"/src/main/java");//输出到哪个目录
        gc.setAuthor("liu");
        gc.setOpen(false);
        gc.setFileOverride(false);//是否覆盖
        gc.setServiceName("%sService");//去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);
        //2、设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("study"); 
        pc.setParent("com.liu");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc); // 在com.liu.study包下生成pojo、mapper、service、controller这些包
        //4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");//设置要映射的表名,只需改这里即可! 即自动生成数据库中的哪些表!
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);//是否使用lombok开启注解
        strategy.setLogicDeleteFieldName("deleted");
        //自动填充配置
        TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
        TableFill gmtUpdate = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtUpdate);
        strategy.setTableFillList(tableFills);
        //乐观锁配置
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);//开启驼峰命名
        strategy.setControllerMappingHyphenStyle(true);//localhost:8080/hello_id_2
        mpg.setStrategy(strategy);
        mpg.execute();//执行
    }
}

4、添加依赖:

<dependencies>
      <!--MySQL驱动-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <!-- 可通过version设置版本号 -->
      </dependency>

      <!-- lombok -->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
      </dependency>

      <!-- mybatisplus -->
      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
          <version>3.0.5</version>
      </dependency>
      <!-- 新版乐观锁依赖 -->
      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-generator</artifactId>
          <version>3.4.0</version>
      </dependency>

      <!-- 新版性能分析依赖 -->
      <dependency>
          <groupId>p6spy</groupId>
          <artifactId>p6spy</artifactId>
          <version>3.9.1</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>
      <!--模板引擎 依赖:mybatis-plus代码生成的时候报异常-->
      <dependency>
          <groupId>org.apache.velocity</groupId>
          <artifactId>velocity-engine-core</artifactId>
          <version>2.0</version>
      </dependency>
      <!--配置ApiModel在实体类中不生效-->
      <dependency>
          <groupId>com.spring4all</groupId>
          <artifactId>spring-boot-starter-swagger</artifactId>
          <version>1.5.1.RELEASE</version>
      </dependency>
      <!--freemarker-->
      <dependency>
          <groupId>org.freemarker</groupId>
          <artifactId>freemarker</artifactId>
          <version>2.3.30</version>
      </dependency>
      <!--beetl-->
      <dependency>
          <groupId>com.ibeetl</groupId>
          <artifactId>beetl</artifactId>
          <version>3.3.2.RELEASE</version>
      </dependency>

</dependencies>

5、运行LiuCode类即可!
在这里插入图片描述

1.5 Mybatis-Plus 练习

1.5.0 插件自动根据数据库表生成po、mapper、mapper.xml

1、IDEA连接到数据库

在这里插入图片描述
2、在将要生成的表右键 --> Mybatis generator

在这里插入图片描述
3、做如下配置:

在这里插入图片描述
在弄一下最下面的 mybatisPlus配置

在这里插入图片描述
其他的配置都可以不用配,默认方法也全不勾,用处不大。

生成:

在这里插入图片描述
po实体类:

在这里插入图片描述
mapper接口:

在这里插入图片描述
mapper.xml:

在这里插入图片描述

1.5.1 普通单表查询

在这里插入图片描述

注意:Wrappers.lambdaQuery(.class) 这个类型必须是主表的类型,即查询返回的结果必须是主表的类型。想转为VO的话自己再做处理。

在设置条件语句时,第一个参数可以加一个判空条件,当不为空时条件才生效!

在这里插入图片描述

1.5.1.1 .and() .or() 语句实现复杂逻辑

如果传来的一个值是模糊查询,可能是表中某多个字段的取值。这个时候对传来的模糊查询值判空后,就需要用 or 来检查是哪个字段的取值。

此时应这样写:

在这里插入图片描述
用 .and 来扩上,也就是 A and ( B or C ),不用 .and 的话就变成了 A and B or C,就错了。

sql语句为:

在这里插入图片描述

1.5.2 单表分页查询

在这里插入图片描述

1.5.3 连表查询

引入join依赖:

<!-- mpj -->
<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join-boot-starter</artifactId>
    <version>1.3.8</version>
</dependency>

将发起连表的那个表Mapper 继承自 MPJBaseMapper< PersonInfo>

在这里插入图片描述
然后就可以使用了,连表查询代码如下:

// PersonInfo表 左连接 PersonMobile表
MPJLambdaWrapper<PersonInfo> wrapper = new MPJLambdaWrapper<PersonInfo>()
        .selectAll(PersonInfo.class) // 选择 PersonInfo的所有字段
//                .select(PersonMobile::getMobile) // 选择PersonMobile某一字段 
        .selectAs(PersonMobile::getMobile, PersonInfoVO::getPersonMobile) // 选择PersonMobile某一字段,并改名与自定义返回给前端的VO中的字段名字对应
        .leftJoin(PersonMobile.class, PersonMobile::getName, PersonInfo::getName) // 两表左连接,根据Name连接
        .eq(PersonInfo::getAge, 18) // 年龄=18
        .likeRight(PersonInfo::getName, "康"); // 康%,即以康开头
        
List<PersonInfoVO> list = personInfoMapper.selectJoinList(PersonInfoVO.class, wrapper);
list.forEach(t->{
    System.out.println(t);
});

1.5.4 连表分页查询

// PersonInfo表 左连接 PersonMobile表
MPJLambdaWrapper<PersonInfo> wrapper = new MPJLambdaWrapper<PersonInfo>()
        .selectAll(PersonInfo.class) // 选择 PersonInfo的所有字段
//      .select(PersonMobile::getMobile) // 选择PersonMobile某一字段
        .selectAs(PersonMobile::getMobile, PersonInfoVO::getPersonMobile) // 选择PersonMobile某一字段,并改名与自定义返回给前端的VO中的字段名字对应
        .leftJoin(PersonMobile.class, PersonMobile::getName, PersonInfo::getName) // 两表左连接,根据Name连接
        .eq(PersonInfo::getAge, 18) // 年龄=18
        .likeRight(PersonInfo::getName, "康"); // 康%,即以康开头
        
Page<PersonInfoVO> page = new Page<>(1,3);
List<PersonInfoVO> list = personInfoMapper.selectJoinPage(page, PersonInfoVO.class, wrapper).getRecords();
list.forEach(t->{
    System.out.println(t);
});

1.5.5 更新操作

personInfoMapper.update(null, Wrappers.lambdaUpdate(PersonInfo.class)
//      .set(PersonInfo::getAge, 20) // 直接设置值
        .setSql("age = age + 5") // 在原有值的基础上设置值
        .le(PersonInfo::getAge, 15)); // 条件

1.5.6 实现包含数据库特定函数的分组查询

下面是 QueryWrapper 的实现,用 LambdaQueryMapper 不方便。 感觉还是 XML 更方便

QueryWrapper<DemandUserDemand> queryWrapper = new QueryWrapper<>();
queryWrapper.select("MONTH(create_time) as month", "COUNT(*) as demandNum")
    .eq("YEAR(create_time)", Year.now().getValue())
    .groupBy("MONTH(create_time)")
    .orderByAsc("MONTH(create_time)");

对于一些简单的查询,LambdaQueryWrapper 可能更加直观和方便,而对于一些复杂的查询,可能需要使用 XML 来实现。另外,对于一些数据库特定的函数,如获取月份、日期加减等操作,使用 XML 可能更加直接和方便。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐