MyBatisPlus笔记

1.MyBatisPlus简介

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1.1 官网链接

  • MyBatisPlus官网:https://baomidou.com/#/

1.2 MyBatisPlus特性

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

2.MyBatisPlus快速入门

2.1 官方教程地址

  • MyBatisPlus快速入门:https://baomidou.com/guide/quick-start.html

2.2 快速入门实践

步骤

1、创建数据库,对应脚本如下

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

2、创建数据表,对应脚本输入

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');
  • 显示开发中表必备字段还有version(版本)deleted(逻辑删除)create_time(创建时间)update_time(更新时间),后续步骤会增加。

3、创建SpringBoot项目

4、导入依赖

<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--导入mybatis-plusSpringBoot依赖-->
<!--不要同时导入mybati和mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>

5、连接数据库(配置application.yaml)

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatisplus?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 770880
    driver-class-name: com.mysql.cj.jdbc.Driver
    # spring-boot 2 默认采用高性能的 Hikari 作为连接池 更多配置可以参考 https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
    type: com.zaxxer.hikari.HikariDataSource

6、创建pojo类以及mapper类

//pojo类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
//mapper类
@Repository
public interface UserMapper extends BaseMapper<User> {
	//所有crud都已完成
}

7、在主函数头部添加扫描组件

@MapperScan("com.jyc.mapper")	//添加扫描包
@SpringBootApplication
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}

8、编写测试

@SpringBootTest
class MybatisPlusApplicationTests {
    // 注册组件
    @Autowired
    private UserMapper userMapper;
    // 测试查询数据表内容
    @Test
    void contextLoads() {
        //查询全部内容
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}
  • 读出数据内容说明测试成功

MyBatisPlus笔记

3.MybatisPlus核心功能

3.1 基本CRUD

插入(insert)

  • 测试代码如下
@Test
void testInsert(){
    User user = new User();
    //设置插入数据
    user.setName("Jyc");
    user.setAge(18);
    user.setEmail("508722744@qq.com");
    //执行插入
    userMapper.insert(user);
}
  • 测试结果如图所示

MyBatisPlus笔记

  • 可以发现没有设置id数据的时候,mybatisplus会默认自动帮我们填写一个id进去。原因见3.3自动填充

更新(update)

  • 测试代码如下
@Test
void testInsert(){
    User user = new User();
    //设置更新数据
    user.setName("Jyc");
    user.setAge(18);
    user.setEmail("508722744@qq.com");
    //执行插入
    userMapper.insert(user);
}
  • 测试结果如图所示

MyBatisPlus笔记

  • 在设置更新属性的时候,只要设置了的数据mybatisplus都会动态拼接sql,来更新设置的数据

查询(select)

  • 测试代码如下
@Test
void testSelect(){
    //查询单个id
	User user1 = userMapper.selectById(1L);
    System.out.println(user1);
    
    //查询多个id
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));    
    
    //条件查询
    HashMap<String, Object> map = new HashMap<>();
   	//查询名字为jyc的
    map.put("name","jyc");
    userMapper.selectByMap(map);
}
  • 测试结果如图所示

MyBatisPlus笔记

删除(delete)

  • 测试代码如下
@Test
void testDelete(){
    //删除单个
	userMapper.deleteById(1L);
    
    //删除多个
    userMapper.deleteBatchIds(Arrays.asList(1, 2, 3)); 
    
    //条件删除
    HashMap<String, Object> map = new HashMap<>();
   	//删除名字为jyc的
    map.put("name","jyc");
    userMapper.deleteByMap(map);
}
  • 测试结果如图

MyBatisPlus笔记

3.2 配置日志

通过日志查看sql执行内容,只需要配置application.yaml文件即可

# 配置日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 再次启动测试即可看到日志输出

MyBatisPlus笔记

3.3 主键生成策略

  • 在3.1插入时,发现没有设置id却在插入后会自动添加。原因就是mybatisplus的自动填充机制

  • 知识点拓展:雪花算法

    • snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。
  • 通过设置注解,设置主键的增加方式

public enum IdType{
    AUTO(0),			//数据库id自增(主键比如设置自增)
    NONE(1),			//未设置主键
    INPUT(2),			//手动输入
    ID_WORKER(3),		//默认的全局唯一id(雪花算法)
    UUID(4),			//全局唯一id UUID
    ID_WORKER_STR(5);	//ID_WORKER字符串表示形式
}
@TableId(type = IdType.AUTO)
private Long id;

3.4 自动填充

  • 所有数据表都必须配置create_time(创建时间)update_time(更新时间)两个字段,且应该是自动更新的。

  • 自动填充方式一:数据库级别

    • 在表中新增字段create_timeupdate_time且设置自动更新以及默认值

    MyBatisPlus笔记

  • 自动填充方式二:代码级别

    1、在表中新增字段create_timeupdate_time但是不设置自动更新以及默认值

    MyBatisPlus笔记

    2、在属性类添加自动更新注解

    //在插入时进行更新
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //在插入和更新时进行更新
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    

    3.编写注解实现类

    @Slf4j		//日志打印
    @Component	//将处理器加到IOC容器中
    public class MyObjectHandler implements MetaObjectHandler {
        /**
         * 插入时的填充策略
         *
         * setFieldValByName(String fieldName, 设置的字段名
         *                   Object fieldVal,  设置的字段值
         *                   MetaObject metaObject)
         * */
        @Override
        public void insertFill(MetaObject metaObject) {
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
        /**
         * 更新时的填充策略
         * */
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    

    4.执行SQL语句即可

3.5 乐观锁

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

悲观锁:顾名思义十分悲观,总是认为总是出现问题,无论干什么都会去上锁!再去操作

常见使用字段:version(版本)

  • 乐观锁实现方式:

    • 取出记录时,获取当前version
    • 更新时,带上这个version
    • 执行更新时, set version = newVersion where version = oldVersion
    • 如果version不对,就更新失败
  • 简单例子

    • 存在两个线程要更新同一条数据
    • 初始获取时version = 1
    • 现在任意一个提前提交后,对应数据库的version则变成2
    • 此时如果另外一个线程要提交时,version版本判断不对,则就提交失败
  • 乐观锁代码测试

    1、数据库添加version字段

    MyBatisPlus笔记

    2、实体类添加对应字段

    /**
    * 乐观锁注解
    */
    @Version
    private Integer version;
    

    3、注册组件,创建MyConfig.java

    @Configuration
    @MapperScan("com.jyc.mapper")
    @EnableTransactionManagement
    public class MyConfig {
        /**
         * 注册乐观锁插件
         */
        @Bean
        public OptimisticLockerInterceptor OptimisticLockerInnerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    

    4、成功用例测试

    @Test
    void testVersion(){
        //查询用户信息
        User user = userMapper.selectById(1L);
        System.out.println(user);
        //修改用户信息
        user.setName("jyc");
        //执行修改操作
        userMapper.updateById(user);
    }
    
    • 对应版本修改为二

    MyBatisPlus笔记

    5、失败用例测试

    @Test
    void testVersion(){
        //用户1查询用户信息
        User user1 = userMapper.selectById(1L);
        //用户1修改用户信息
        user1.setName("jyc1");
        //用户2查询用户信息
        User user2 = userMapper.selectById(1L);
        //用户2修改用户信息
        user2.setName("jyc2");
        //用户2执行修改操作
        userMapper.updateById(user2);
        //用户1执行修改操作
        userMapper.updateById(user1);
    }
    
    • 只会执行用户2操作而不会执行用户1

    MyBatisPlus笔记

3.6 分页查询

1、注册组件

/**
* 注册分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

2、直接使用page对象即可

@Test
void testPage(){
    //查询第0页5个数据
    Page<User> page = new Page<>(0,5);
    userMapper.selectPage(page,null);
}

3、查询结果如图

MyBatisPlus笔记

3.7 逻辑删除

物理删除:直接从数据库删除

逻辑删除:没从数据库删除,通过变量使其失效

1、数据表添加deleted字段

MyBatisPlus笔记

2、实体类中添加

/**
* 逻辑删除
*/
@TableLogic
private Integer deleted;

3、配置逻辑删除

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1		#删除时为1
      logic-not-delete-value: 0	#没删除时为0

4、删除测试

@Test
void testDelete(){
	userMapper.deleteById(2L);
}
  • 删除结果如下,逻辑位设置为1但并没有真正删除

MyBatisPlus笔记

3.8 性能分析插件

性能分析拦截器,用于输出每条SQL语句及其执行时间

  • 具体操作见官网:https://baomidou.com/guide/p6spy.html

3.9 条件构造器(重点)

条件构造器Wrapper相当于在调用SQL语句的时候,添加一些限制条件,完成一些高级的SQL操作。

1、测试样例1

@Test
void testWrapper1(){
    //查询邮箱和用户名不为空,且年龄大于等于12的信息
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.isNotNull("name")
        .isNotNull("email")
        .ge("age",12);
    userMapper.selectList(wrapper);
}
  • 测试结果如图

MyBatisPlus笔记

2、测试样例2

@Test
void testWrapper2(){
    //查询名字为test
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","test");
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}
  • 测试结果如图

MyBatisPlus笔记

3、测试样例3

@Test
void testWrapper3(){
    //查询年龄在10~20之间的人
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",10,20);
    userMapper.selectCount(wrapper);
}
  • 测试结果如图

MyBatisPlus笔记

3.10 代码生成器

帮助快速生成基本CRUD代码

1、导入依赖

2、编写代码生成器规则

3、运行代码生成器

  • 导入依赖
<!-- MyBatis Plus 代码生成工具 -->
	<dependency>
		<groupId>com.baomidou</groupId>
		<artifactId>mybatis-plus-generator</artifactId>
		<version>3.4.1</version>
	</dependency>
	<dependency>
		<groupId>org.apache.velocity</groupId>
		<artifactId>velocity-engine-core</artifactId>
		<version>2.2</version>
	</dependency>
  • 编写代码生成器
package com.jyc.mybatisplus;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
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.TemplateConfig;
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 com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.fasterxml.jackson.databind.deser.SettableAnyProperty;

import java.util.ArrayList;
import java.util.Scanner;

/**
 * @author Jyc
 * @date 2021/1/3
 */
public class CodeGenerator {
    /**
     * 设置作者
     */
    private final static String AUTHOR = "Jyc";
    /**
     * 驱动名称
     */
    private final static String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
    /**
     * 用户名
     */
    private final static String USER_NAME = "root";
    /**
     * 用户密码
     */
    private final static String PASSWORD = "770880";
    /**
     * JDBC链接地址
     */
    private final static String JDBC_URL = "jdbc:mysql://127.0.0.1:3306/mybatisplus?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true";

    /**
     * 数据库类型
     */
    private final static DbType DB_TYPE = DbType.MYSQL;

    /**
     * 模块名
     */
    private final static String MODULE = "generator";
    /**
     * 项目路径
     */
    private String projectPath = System.getProperty("user.dir");
    /**
     * 公共包路径
     */
    private String parentPackage = "com.jyc";
    /**
     * 逻辑删除字段名
     */
    private String logicDelete = "deleted";

    /**
     * 主函数入口
     *
     * @param args
     */
    public static void main(String[] args) {
        CodeGenerator codeGenerator = new CodeGenerator();
        codeGenerator.execute();
    }

    /**
     * 读取控制台内容
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入" + tip + ":");
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (ipt != null && !ipt.trim().isEmpty()) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    /**
     * 主函数运行
     */
    public void execute() {
        // 代码生成器对象
        AutoGenerator mpg = new AutoGenerator();
        // 1.全局配置
        GlobalConfig gc = new GlobalConfig()
                // 设置输出目录
                .setOutputDir(projectPath + "/src/main/java")
                // 设置作者
                .setAuthor(AUTHOR)
                // 设置关闭资源管理器
                .setOpen(false)
                // 设置文件内容覆盖
                .setFileOverride(true)
                // 设置Service的I前缀
                .setServiceName("%sService")
                // 设置主键递增策略
                .setIdType(IdType.AUTO)
                // 设置日期类型
                .setDateType(DateType.ONLY_DATE);
        // 导入全局配置
        mpg.setGlobalConfig(gc);
        // 2.设置数据源
        DataSourceConfig dataSourceConfig = new DataSourceConfig()
                // 设置数据库URL地址
                .setUrl(JDBC_URL)
                // 设置数据库驱动名称
                .setDriverName(DRIVER_NAME)
                // 设置数据库用户名
                .setUsername(USER_NAME)
                // 设置数据库密码
                .setPassword(PASSWORD)
                // 设置数据库类型
                .setDbType(DB_TYPE);
        // 导入数据库配置
        mpg.setDataSource(dataSourceConfig);
        // 3.模块的配置
        PackageConfig pc = new PackageConfig()
                // 设置模块上级
                .setParent(parentPackage)
                // 设置模块名
                .setModuleName(MODULE)
                .setEntity("entity")
                .setMapper("mapper")
                .setService("server")
                .setController("controller");
        // 导入模块配置
        mpg.setPackageInfo(pc);
        // 4.策略配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFillS = new ArrayList<>();
        tableFillS.add(createTime);
        tableFillS.add(updateTime);
        StrategyConfig strategy = new StrategyConfig()
                .setChainModel(true)
                .setEntityLombokModel(true)
                .setRestControllerStyle(true)
                .setTableFillList(tableFillS)
                .setLogicDeleteFieldName(logicDelete)
                .setEntityTableFieldAnnotationEnable(true)
                .setNaming(NamingStrategy.underline_to_camel)
                .setColumnNaming(NamingStrategy.underline_to_camel)
                .setInclude(scanner("表名,多个英文逗号分割").split(","))
                .setRestControllerStyle(true)
                .setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        mpg.execute();
    }
}
上一篇:MybatisPlus基础


下一篇:spring-boot集成mybatis-plus