Mybatis-Plus详细讲解(二)3万字的整理慢慢看

MyBatis-plus讲解篇

前言

这篇博文是接着前一段时间的MyBatis-Plus详细讲解(一)续写,链接如下

链接 地址
MyBatis-Plus详细讲解(一) 点击进入

话不多说,继续干

注解

具体有如下注解

注解名 说明
@TableName 表名注解
@TableId 主键注解
@TableField 字段注解(非主键)
@Version 乐观锁注解
@EnumValue 通枚举类注解
@TableLogic 表字段逻辑处理注解
@KeySequence 序列主键策略

@InterceptorIgnore:该注解作用于 xxMapper.java 方法之上 各属性代表对应的插件 各属性不给值则默认为 false 设置为 true 忽略拦截

SpringBoot整合MyBatis-plus快速使用

依赖

项目我这边已经有了相关测试demo,大家那就自己去创建一个吧,创建好后,依赖如下
主要依赖如下
1:SpringBoot
2:MyBatis-plus
3:SpringBoot web
4:MySQL
5:Swagger2
6:Lombok

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.uncletj</groupId>
    <artifactId>mybatis-plus-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>mybatis-plus-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!--SpringBoot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

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

        <!--springboot-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--MySQL-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--Swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.4.0</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.4.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

数据库测试表

接下来既然后端框架已经搭建好了那么数据库在创建一个吧,我就不用之前那个了,为了方便我这里直接把数据库中的测试表给出大家,直接粘贴过去就行了

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for intro
-- ----------------------------
DROP TABLE IF EXISTS `intro`;
CREATE TABLE `intro` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `name` varchar(40) COLLATE utf8_bin NOT NULL COMMENT '姓名',
  `age` int NOT NULL COMMENT '年龄',
  `gender` varchar(2) COLLATE utf8_bin DEFAULT NULL COMMENT '性别',
  `hobby` varchar(40) COLLATE utf8_bin DEFAULT NULL COMMENT '兴趣爱好',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

-- ----------------------------
-- Records of intro
-- ----------------------------
INSERT INTO `intro` VALUES ('1', '小红帽', '7', '女', '我是小红帽,我喜欢我的外婆');
INSERT INTO `intro` VALUES ('2', '小明', '12', '男', '我是小明,我喜欢学习');
INSERT INTO `intro` VALUES ('3', '小亮', '13', '男', '我是小亮,我喜欢运动');

操作完后在表中可直接有几条测试数据
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

配置文件(YML)

#mysql
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/testdb?characterEncoding=utf-8&serverTimezone=GMT%2B8
    username: root
    password: root
#端口号设置
server:
  port: 8080

配置类

在这里我写了一些配置类,主要的目的也是为了后期的一个测试效果更好,主要如下
Swagger2配置类

package com.uncletj.mybatisplusdemo.config;

import com.google.common.collect.Sets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @Author uncletj
 * @Date 2021/4/22 11:38
 * @Version SpringBoot 2.2.2
 * @projectName
 */
@Configuration//配置类
@EnableSwagger2//开启Swagger2的自动配置
public class SwaggerConfig {
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                //协议,http或https
                .protocols(Sets.newHashSet("http"))
                .apiInfo(apiInfo())
                .select()
                //controller扫描路径
                .apis(RequestHandlerSelectors.basePackage("com.uncletj.mybatisplusdemo.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("mybatis-plus-demo")
                .version("1.0")
                .description("demo version 1.0")
                .build();
    }
}

返回类枚举

package com.uncletj.mybatisplusdemo.config;

/**
 * @Author uncletj
 * @Date 2021/4/22 14:58
 * @Version SpringBoot 2.2.2
 * @projectName 返回枚举
 */
public enum ResponseCode {
    /** 成功 */
    SUCCESS("200", "成功"),

    /** 操作失败 */
    ERROR("500", "操作失败");

    private ResponseCode(String value, String msg){
        this.val = value;
        this.msg = msg;
    }

    public String val() {
        return val;
    }

    public String msg() {
        return msg;
    }

    private String val;
    private String msg;
}

统一返回配置类

package com.uncletj.mybatisplusdemo.config;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @Author uncletj
 * @Date 2021/4/22 14:59
 * @Version SpringBoot 2.2.2
 * @projectName 统一返回类
 */
@Data
@ApiModel(description = "返回响应式数据")
public class ResultData {

    @ApiModelProperty(value = "编码")
    private String code;

    @ApiModelProperty(value = "是否成功")
    private String msg;

    @ApiModelProperty("返回对象")
    private Object data;

    private static ResultData resultData(String code, String msg, Object data) {
        ResultData resultData = new ResultData();
        resultData.setCode(code);
        resultData.setMsg(msg);
        resultData.setData(data);
        return resultData;
    }

    //返回数据成功
    public static ResultData success(Object data, String msg) {
        return resultData(ResponseCode.SUCCESS.val(), msg, data);
    }

    //返回数据报错
    public static ResultData fail(String code, String msg) {
        return resultData(ResponseCode.ERROR.val(), ResponseCode.ERROR.msg(), null);
    }
}

实体类

因为我们在刚刚引入了一个lombok的依赖,所以使用@Data注解可以为我们省略getter与setter方法,这样代码量也会减少很多
Intro.java

package com.uncletj.mybatisplusdemo.po;

import lombok.Data;

/**
 * @Author uncletj
 * @Date 2021/4/22 14:43
 * @Version SpringBoot 2.2.2
 * @projectName 个人介绍实体类
 */
@Data
public class Intro {

    /**
     * 主键id
     */
    private int id;

    /**
     * 名称
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 性别
     */
    private String gender;

    /**
     * 兴趣爱好
     */
    private String hobby;
}

mapeer

这里直接继承BaseMapper,可以省去xml文件,也可以通过自己去创建一个xml文件编写sql
IntroMapper .java

package com.uncletj.mybatisplusdemo.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.uncletj.mybatisplusdemo.po.Intro;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Author uncletj
 * @Date 2021/4/22 11:44
 * @Version SpringBoot 2.2.2
 * @projectName
 */
@Mapper
public interface IntroMapper extends BaseMapper<Intro> {

}

Service

IntroService .java

package com.uncletj.mybatisplusdemo.service;

import com.uncletj.mybatisplusdemo.po.Intro;
import java.util.List;

/**
 * @Author uncletj
 * @Date 2021/4/22 14:52
 * @Version SpringBoot 2.2.2
 * @projectName
 */
public interface IntroService {

    List<Intro>getBySelectIntro();
}

impl

IntroServiceImpl .java

package com.uncletj.mybatisplusdemo.service.impl;

import com.uncletj.mybatisplusdemo.mapper.IntroMapper;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @Author uncletj
 * @Date 2021/4/22 14:53
 * @Version SpringBoot 2.2.2
 * @projectName
 */
@Service
public class IntroServiceImpl implements IntroService {

    @Resource
    private IntroMapper introMapper;

    @Override
    public List<Intro> getBySelectIntro() {
        return introMapper.selectList(null);
    }
}

控制层

IntroController.java

package com.uncletj.mybatisplusdemo.controller;

import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Author uncletj
 * @Date 2021/4/22 12:00
 * @Version SpringBoot 2.2.2
 * @projectName
 */
@RestController
@RequestMapping(value = "intro")
public class IntroController {

    @Autowired
    private IntroService introService;

    /**
     * 查询所有数据
     * @return
     */
    @GetMapping("/list")
    public ResultData getByIntroList(){
        try {
            List<Intro> list = introService.getBySelectIntro();
            return ResultData.success(list,"查询数据成功");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
        }
    }
}

这样一个基本的操作就完成了,就是这么简单,先去测试看看结果吧!
Mybatis-Plus详细讲解(二)3万字的整理慢慢看
测试之后是没问题的,大家再来看下我这边的一个控制台
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

日志输出

有日志输出,这个十分简单,只需要向我们的yml文件内添加以下配置即可,这样就可以实时观测我们的sql记录了

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

当然在我的另外一篇文章中有一个logback的日志输出,可以可以观测sql记录的,有兴趣也可以去看看我把链接地址放在下面

链接 地址
设置logback.xml日志打印记录 点击进入

这个呈现的效果如下,好处是能确定在某个时间段执行了那一部分的sql
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

代码生成器

介绍

AutoGenerator 简介
  AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。与 mybatis 中的 mybatis-generator-core 类似。这个也是MyBatis-plus的一个很实用的一个功能,下面我们来看看怎么进行使用吧

删除之前的模块

Mybatis-Plus详细讲解(二)3万字的整理慢慢看
可以看到我现在是把之前的模块全部删除掉了的,这个时候不要慌,我们用代码生成器一键生成,并且我还要变的比以前更全面,首先我们先去引入AutoGenerator 的依赖吧

		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>
        <!-- 添加 模板引擎 依赖 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>

紧接着就可以开始编写生成类了,下面写入一个AutoGeneratorTest的测试类,具体如下

package com.uncletj.mybatisplusdemo;

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.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;
/**
 * @Author uncletj
 * @Date 2021/4/22 15:40
 * @Version SpringBoot 2.2.2
 * @projectName MyBatis-plus生成器
 */

public class AutoGenerateTest {
    @Test
    public void autoGenerate() {
        // 1、代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        // 填写代码生成的目录(需要修改)
        String projectPath = "D://uploads//mybatis-plus-demo";
        // 拼接出代码最终输出的目录
        gc.setOutputDir(projectPath + "/src/main/java");
        // 配置开发者信息(可选)(需要修改)
        gc.setAuthor("uncletj");
        // 配置是否打开目录,false 为不打开(可选)
        gc.setOpen(false);
        // 实体属性 Swagger2 注解,添加 Swagger 依赖,开启 Swagger2 模式(可选)
        gc.setSwagger2(true);
        // 重新生成文件时是否覆盖,false 表示不覆盖(可选)
        gc.setFileOverride(false);
        // 配置主键生成策略,此处为 ASSIGN_ID(可选)
        gc.setIdType(IdType.ASSIGN_ID);
        // 配置日期类型,此处为 ONLY_DATE(可选)
        gc.setDateType(DateType.ONLY_DATE);
        // 默认生成的 service 会有 I 前缀
        gc.setServiceName("%sService");
        mpg.setGlobalConfig(gc);

        // 3、数据源配置(需要修改)
        DataSourceConfig dsc = new DataSourceConfig();
        // 配置数据库 url 地址
        dsc.setUrl("jdbc:mysql://localhost:3306/testdb?characterEncoding=utf-8&serverTimezone=GMT%2B8");
        // 可以直接在 url 中指定数据库名
        // dsc.setSchemaName("testdb");
        // 配置数据库驱动
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        // 配置数据库连接用户名
        dsc.setUsername("root");
        // 配置数据库连接密码
        dsc.setPassword("root");
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        // 配置父包名(需要修改)
        pc.setParent("com.uncletj");
        // 配置模块名(需要修改)
        pc.setModuleName("mybatisplusdemo");
        // 配置 po 包名
        pc.setEntity("po");
        // 配置 mapper 包名
        pc.setMapper("mapper");
        // 配置 service 包名
        pc.setService("service");
        // 配置 controller 包名
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 5、策略配置(数据库表配置)
        StrategyConfig strategy = new StrategyConfig();
        // 指定表名(可以同时操作多个表,使用 , 隔开)(需要修改)
        strategy.setInclude("intro");
        // 配置数据表与实体类名之间映射的策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        // 配置数据表的字段与实体类的属性名之间映射的策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // 配置 lombok 模式
        strategy.setEntityLombokModel(true);
        // 配置 rest 风格的控制器(@RestController)
        strategy.setRestControllerStyle(true);
        // 配置驼峰转连字符
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);

        // 6、执行代码生成操作
        mpg.execute();
    }
}

Mybatis-Plus详细讲解(二)3万字的整理慢慢看
执行后结果如上的话你的模块也会直接显示出来了,我生成之后的模块如下,是不是有种很爽的感觉,突然之间少了一大批步骤
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

接口测试

下面我们什么也不做,直奔控制类而去写一个接口,看看能不能吧

package com.uncletj.mybatisplusdemo.controller;


import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author uncletj
 * @since 2021-04-22
 */
@RestController
@RequestMapping("/intro")
public class IntroController {

    @Autowired
    private IntroService introService;

    @GetMapping("/list")
    public ResultData getBySelectIntroList() {
        try {
            List<Intro> list = introService.list();
            return ResultData.success(list,"查询数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
        }
    }
}

测试一下看看,结果就在眼前了
Mybatis-Plus详细讲解(二)3万字的整理慢慢看
这个是真的,只是一个代码生成器,上控制类写一个接口后调用业务层直接出来数据!
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

IService

就是这么爽,究竟是什么让我们这么爽快的就把数据给传出来了,下面去一探究竟,一个ctrl+鼠标左键,我立马就跳转到了一个神奇的地方,就是它《IService》
IService.java
还真的是太暖心了吧,下面基本上都是一些CRUD操作,相信大家都能看得懂,用多了慢慢就熟悉了,我也就不过与太多的介绍了吧

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

package com.baomidou.mybatisplus.extension.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;

public interface IService<T> {
    int DEFAULT_BATCH_SIZE = 1000;

    default boolean save(T entity) {
        return SqlHelper.retBool(this.getBaseMapper().insert(entity));
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean saveBatch(Collection<T> entityList) {
        return this.saveBatch(entityList, 1000);
    }

    boolean saveBatch(Collection<T> entityList, int batchSize);

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean saveOrUpdateBatch(Collection<T> entityList) {
        return this.saveOrUpdateBatch(entityList, 1000);
    }

    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

    default boolean removeById(Serializable id) {
        return SqlHelper.retBool(this.getBaseMapper().deleteById(id));
    }

    default boolean removeByMap(Map<String, Object> columnMap) {
        Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);
        return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));
    }

    default boolean remove(Wrapper<T> queryWrapper) {
        return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));
    }

    default boolean removeByIds(Collection<? extends Serializable> idList) {
        return CollectionUtils.isEmpty(idList) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(idList));
    }

    default boolean updateById(T entity) {
        return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
    }

    default boolean update(Wrapper<T> updateWrapper) {
        return this.update((Object)null, updateWrapper);
    }

    default boolean update(T entity, Wrapper<T> updateWrapper) {
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean updateBatchById(Collection<T> entityList) {
        return this.updateBatchById(entityList, 1000);
    }

    boolean updateBatchById(Collection<T> entityList, int batchSize);

    boolean saveOrUpdate(T entity);

    default T getById(Serializable id) {
        return this.getBaseMapper().selectById(id);
    }

    default List<T> listByIds(Collection<? extends Serializable> idList) {
        return this.getBaseMapper().selectBatchIds(idList);
    }

    default List<T> listByMap(Map<String, Object> columnMap) {
        return this.getBaseMapper().selectByMap(columnMap);
    }

    default T getOne(Wrapper<T> queryWrapper) {
        return this.getOne(queryWrapper, true);
    }

    T getOne(Wrapper<T> queryWrapper, boolean throwEx);

    Map<String, Object> getMap(Wrapper<T> queryWrapper);

    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

    default int count() {
        return this.count(Wrappers.emptyWrapper());
    }

    default int count(Wrapper<T> queryWrapper) {
        return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));
    }

    default List<T> list(Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectList(queryWrapper);
    }

    default List<T> list() {
        return this.list(Wrappers.emptyWrapper());
    }

    default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectPage(page, queryWrapper);
    }

    default <E extends IPage<T>> E page(E page) {
        return this.page(page, Wrappers.emptyWrapper());
    }

    default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectMaps(queryWrapper);
    }

    default List<Map<String, Object>> listMaps() {
        return this.listMaps(Wrappers.emptyWrapper());
    }

    default List<Object> listObjs() {
        return this.listObjs(Function.identity());
    }

    default <V> List<V> listObjs(Function<? super Object, V> mapper) {
        return this.listObjs(Wrappers.emptyWrapper(), mapper);
    }

    default List<Object> listObjs(Wrapper<T> queryWrapper) {
        return this.listObjs(queryWrapper, Function.identity());
    }

    default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
        return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
    }

    default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectMapsPage(page, queryWrapper);
    }

    default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
        return this.pageMaps(page, Wrappers.emptyWrapper());
    }

    BaseMapper<T> getBaseMapper();

    default QueryChainWrapper<T> query() {
        return ChainWrappers.queryChain(this.getBaseMapper());
    }

    default LambdaQueryChainWrapper<T> lambdaQuery() {
        return ChainWrappers.lambdaQueryChain(this.getBaseMapper());
    }

    default UpdateChainWrapper<T> update() {
        return ChainWrappers.updateChain(this.getBaseMapper());
    }

    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
        return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());
    }

    default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
        return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
    }
}

CRUD操作

为提升观看效果,我在此实现一遍一些简单的crud操作,其实在于MyBatis-plus提供的BaseMapper还是IService它是为我们提供了很大的方便,但是复杂的sql还是需要我们自己去完成,下面我也只做一些简单的测试,所有测试如下

package com.uncletj.mybatisplusdemo.controller;

import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import io.swagger.annotations.ApiImplicitParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author uncletj
 * @since 2021-04-22
 */
@RestController
@RequestMapping("/intro")
public class IntroController {

    @Autowired
    private IntroService introService;

    /**
     * 查询所有数据信息
     * @return
     */
    @GetMapping("/list")
    public ResultData getBySelectIntroList() {
        try {
            List<Intro> list = introService.list();
            return ResultData.success(list,"查询数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
        }
    }


    /**
     * 根据Id查询数据信息
     * @param id
     * @return
     */
    @GetMapping("byid")
    @ApiImplicitParam(name = "id",value = "id",dataType = "int",paramType = "query",required = true)
    public ResultData getIntroById(int id){
        try {
            Intro intro =introService.getById(id);
            return ResultData.success(intro,"查询数据成功");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
        }
    }

    /**
     * 添加数据
     * @param intro
     * @return
     */
    @PostMapping("/insert")
    @ApiImplicitParam(name = "Intro",value = "Intro",dataType = "class",paramType = "body")
    public ResultData getByIntroInsert(@RequestBody Intro intro){
        try {
            boolean ins =introService.save(intro);
            if (ins==true){
                return ResultData.success(ins,"添加数据成功");
            }
            return ResultData.fail(ResponseCode.ERROR.val(),"添加中出现异常,请查看");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"添加数据失败");
        }
    }

    /**
     * 根据id删除数据信息
     * @param intro
     * @return
     */
    @DeleteMapping("/delete")
    @ApiImplicitParam(name = "id",value = "id",dataType = "int",paramType = "query",required = true)
    public ResultData getByIntroDel(Intro intro){
        try {
            boolean id =introService.removeById(intro.getId());
            if (id==true){
                return ResultData.success(id,"删除数据成功");
            }
            return ResultData.fail(ResponseCode.ERROR.val(),"删除中出现异常,请查看");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"删除数据失败");
        }
    }

    /**
     * 根据Id修改数据信息
     * @param intro
     * @return
     */
    @PutMapping("update")
    @ApiImplicitParam(name = "Intro",value = "Intro",dataType = "class",paramType = "body")
    public ResultData getByIntroUpdate(@RequestBody Intro intro){
        try {
            boolean upl =introService.updateById(intro);
            if (upl==true){
                return ResultData.success(intro,"修改数据失败");
            }
            return ResultData.fail(ResponseCode.ERROR.val(),"修改中出现异常,请查看");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"修改数据失败");
        }
    }
}


以上的操作图如下

接口名称 作用
list 查询所有数据信息
byid 根据Id查询数据信息
insert 添加数据
delete 根据id删除数据
update 根据id修改数据

Swagger接口测试图如下
Mybatis-Plus详细讲解(二)3万字的整理慢慢看
swagger的使用我在之前也是有做过一篇博客去介绍了一下,有兴趣的可以了解一下,Swagger是一个后端接口测试工具,使用也是十分的简单,链接如下

链接 地址
SpringBoot集成Swagger实现api接口文档 点击进入

分页插件

编写配置类

这个类必须配置!!!

package com.duodf.uncletj.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * <p>
 *  分页插件配置类
 * </p>
 *
 * @author uncletj
 * @since 2021-04-22
 */
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {

    /**
     * mybatis-plus分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
}

然后我又直接写控制层了,说实话自带的接口用着真香
Mybatis-Plus详细讲解(二)3万字的整理慢慢看

编写控制层

/**
     * 分页查找数据信息
     * @return
     */
    @GetMapping("/page")
    public ResultData getByIntroPageList(){
        try {
            Page<Intro> page = new Page<>(1,2);
            introService.page(page);
            return ResultData.success(page,"查询数据成功");
        }catch (Exception e){
            e.printStackTrace();
            return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
        }
    }

测试

Mybatis-Plus详细讲解(二)3万字的整理慢慢看

把这个接口放到你的控制层就好了,当然我这里的初始数与分页数是定死了的,如果想变活的那也是十分简单,直接配置一个分页的工具类就好了,分页都轻松了,这就特别爽了吧,下面再来了解最后一个内容吧,乐观锁

乐观锁

何为悲欢锁

悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制

何为乐观锁

乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量

乐观锁、悲观锁使用场景

乐观锁一般用于读比较多的场合,尽量减少加锁的开销。
悲观锁一般用于写比较多的场合,尽量减少 类似 乐观锁重试更新引起的性能开销。

乐观锁两种实现方式

选项 操作
第一种 通过版本号机制实现
第二种 通过 CAS 算法实现

本次我就使用第一种方式去实现,接下来继续表演

配置乐观锁插件

在我们的MyBatis-plus配置类下配置如下

/**
 * 乐观锁插件
 * @return 乐观锁插件的实例
 */
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

数据加入版本号

Mybatis-Plus详细讲解(二)3万字的整理慢慢看

实体类加入对应的注解

	/**
     * 版本号(用于乐观锁, 默认为 1)
     */
    @Version
    @TableField(fill = FieldFill.INSERT)
    private Integer version;

自定义类Handler

package com.uncletj.mybatisplusdemo.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @Author uncletj
 * @Date 2021/4/22 
 * @projectName 自定义
 */
@Component
public class MyBatisHanlder implements MetaObjectHandler {


    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "version", Integer.class, 1);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }

}

测试

接下来就可以测试了!我这边写了一个测试类

package com.uncletj.mybatisplusdemo;

import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
class MybatisPlusDemoApplicationTests {

    @Resource
    private IntroService introService;

    @Test
    void contextLoads() {
        Intro intro = new Intro();
        intro.setName("藤井").setAge(12).setGender("无").setHobby("不知道些什么兴趣");
        introService.save(intro);
        introService.list().forEach(System.out::println);
        intro.setName("藤井大叔不骄傲");
        introService.update(intro,null);
        introService.list().forEach(System.out::println);
        }
}

查看结果
Mybatis-Plus详细讲解(二)3万字的整理慢慢看
根据结果得出,首先添加之前版本号是为1,修改之后查询出来的版本号为2
————————————————————————————————————————
这版就到此结束了 ,基本上MyBatis-plus比较实用的功能都应该是列出来了,如有缺漏的,还请指教
Mybatis-Plus详细讲解(二)3万字的整理慢慢看
不要认为自己很强,也不要以为自己很弱,迷茫不是归宿

上一篇:mvc传递json数据到view简单实例


下一篇:一个List请求分页