MyBatis-Plus

1、简介

​ MyBatis-Plus 是一个 Mybatis 增强版工具,在 MyBatis 上扩充了其他功能没有改变其基本功能,为了简化开发提交效率而存在。

​ 官网地址:MyBatis-Plus文档

2、特性

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

3、快速入门

前提环境:

  • 拥有 Java 开发环境以及相应 IDE
  • 熟悉 Spring Boot
  • 熟悉 Maven

1)创建数据库

创建user表:

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

2)创建项目

  • 创建一个空的 Spring Boot 工程

  • 添加依赖

    <!-- mybatis-plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.3</version>
    </dependency>
    <!-- lombok 简化代码工具 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- 数据库连接 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    

    注意:mybatis-plus和mybatis最好不要同时导入,可能会出现版本冲突问题。

  • 项目application.yml中配置数据库连接

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/mybatis_plus_demo?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    
  • 创建实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class user {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • 编写dao层

    //不需要写xml了,只需要继承基础接口 BaseMapper
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
        //所有的CRUD已经被完成
    }
    
  • 扫描mapper:启动类添加@MapperScan注解

    //扫描mapper文件夹
    @MapperScan("com.lbb.mybatis_plus_demo.mapper")
    @SpringBootApplication
    public class MybatisPlusDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusDemoApplication.class, args);
        }
    }
    
  • 测试

    @SpringBootTest
    class MybatisPlusDemoApplicationTests {
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void getUserList(){
            //mybatis-plus参数是wrapper(条件构造器),这里查询全部直接为空即可
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    }
    

3) 配置日志

#配置日志
mybatis-plus:
  configuration:
    #控制台输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4、CRUD扩展

1)插入和主键生成策略

@Test
public void testInsert(){
    User user = new User(null,"lbb",24,"luckly@163.com");
    int i = userMapper.insert(user);//自动回填id
    System.out.println(i);
    System.out.println(user);
}
  • 主键生成策略

    上面插入会生成id,此id使用的是主键生成策略,这里采用的Snowflake(雪花算法)。

    • 雪花算法

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

    • 修改id类型

      在实体类上添加@TableId注解

      @TableId(type = IdType.ASSIGN_ID)
      private Long id;
      

    @TableId注解属性如下:

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

    type类型中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)

2)更新和自动填充

//测试更新
@Test
public void testUpdate(){
    User user = new User(1408073558332645379L,"lbb",18,"luckly@163.com");
    int i = userMapper.updateById(user);
    System.out.println(i);
}

所有的sql是自动动态帮你配置的,只需要在参数实体类里赋值即可!

  • 自动填充

    创建时间和修改时间一般都是根据操作自动化完成的!一般不希望手动更新!

    阿里开发手册明确规定:所有的数据库表必须要有的两个字段:gmt_create(数据创建时间),gmt_modified(数据修改时间),并且需要自动化!

    • 数据库操作(工作中不建议修改数据库)

      1、在表中新增字段,create_time、update_time,默认值当前时间,update_time会根据更新时间更新

      2、在实体类中添加createTime和updateTime字段。

      3、更新查看即可!

    • 代码级别(推荐,不直接操作数据库)

      1、清除数据库时间的设置

      2、实体类添加注解

      @TableField(fill = FieldFill.INSERT)
      private Date createTime;
      @TableField(fill = FieldFill.INSERT_UPDATE)
      private Date updateTime;
      

    FieldFill属性:

    public enum FieldFill {
        /**
         * 默认不处理
         */
        DEFAULT,
        /**
         * 插入填充字段
         */
        INSERT,
        /**
         * 更新填充字段
         */
        UPDATE,
        /**
         * 插入和更新填充字段
         */
        INSERT_UPDATE
    }
    

    ​ 3、自定义实现类 MyMetaObjectHandler

    @Slf4j //日志
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        //插入时的填充策略
        @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、更新查看即可!

3)乐观锁(面试重点)

乐观锁:当要更新一条记录的时候,总是认为这条记录没有被别人更新,如果出现问题就再次更新值测试

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion,newVersion一般是version+1
  • 如果version不对,就更新失败
  • 给数据库增加version字段,默认值为1

  • 实体类加对应的字段,并加上@Version注解

    @Version
    private Integer version;
    
  • 注册组件

    编写配置类:

    @EnableTransactionManagement //事务
    //扫描mapper文件夹 启动类不需要再扫描可以
    @MapperScan("com.lbb.mybatis_plus_demo.mapper")
    @Configuration //配置类
    public class MybatisPlusConfig {
        //注册乐观锁插件
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
    }
    
  • 测试

    //测试乐观锁
    @Test
    public void testOptimisticLocker(){
        User user = userMapper.selectById(1L);
        user.setName("测试乐观锁");
        user.setAge(18);
        userMapper.updateById(user);
    }
    

4)查询操作和分页查询

//测试查询
@Test
public void getUserList(){
    //多id查询
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L,2L,3L));
    users.forEach(System.out::println);
    
    //mybatis-plus参数是wrapper(条件构造器),这里查询全部直接为空即可
    List<User> users2 = userMapper.selectList(null);
    users2.forEach(System.out::println);
    
    //通过条件查询 使用map封装,但是通常会使用条件构造器查询
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","lbb");
    map.put("age",18);
    List<User> users3 = userMapper.selectByMap(map);
    users3.forEach(System.out::println);
}
  • 分页 -> PaginationInnerInterceptor

    • 在配置类注册器里面添加分页插件:

      @EnableTransactionManagement //事务
      //扫描mapper文件夹 启动类不需要再扫描可以
      @MapperScan("com.lbb.mybatis_plus_demo.mapper")
      @Configuration //配置类
      public class MybatisPlusConfig {
          //注册乐观锁插件
          @Bean
          public MybatisPlusInterceptor mybatisPlusInterceptor() {
              MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
              interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
              
              //添加分页插件
              interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
              return interceptor;
          }
      }
      
    • 测试分页

      //测试分页查询
      @Test
      public void testPage(){
          //参数1:当前页   参数2:页面大小
          Page<User> page = new Page<>(1,5);//从第一页开始 每页5条数据
          userMapper.selectPage(page, null);
          page.getRecords().forEach(System.out::println);
      }
      

5)删除与逻辑删除

  • 基本删除
//测试删除
@Test
public void testDeletse(){
    //id删除
    userMapper.deleteById(1408073558332645378L);
    //id批量删除
    userMapper.deleteBatchIds(Arrays.asList(1408073558332645379L,1408073558332645380L));
    //条件删除,一般用条件构造器,这里用map
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","lbb");
    userMapper.deleteByMap(map);
}
  • 逻辑删除

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

    逻辑删除:没有被移除,而是通过变量标记,使数据失效。 deleted = 0 => deleted = 1

    • 在数据库表中增加一个deleted字段

    • 实体类中增加属性,添加@TableLogic注解

      @TableLogic
      private Integer deleted;
      
    • 在 application.yml 配置:

      mybatis-plus:
        global-config:
          db-config:
            #logic-delete-field: deleted  # 全局逻辑删除的实体字段名(可写可不写)
            logic-delete-value: 1 # 逻辑已删除值(默认为 1)
            logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      
    • 测试删除查询即可!

5、性能分析插件

mybatis-plus提供的有性能分析插件,如果超过固定时间就会停止运行!

该功能在3.2.0版本被废除,3.2.0以上版本可以使用性能分析打印插件,3.2.0以下版本可以接着使用

  • 在配置类中配置插件

     @Bean
     @Profile({"dev","test"}) // 指定环境
     public PerformanceInterceptor performanceInterceptor() {
     	PerformanceInterceptor interceptor = new PerformanceInterceptor();
        // sql美化打印
    	interceptor.setFormat(true);
     	// 设置SQL超时时间: 毫米
     	interceptor.setMaxTime(500);
    	 //格式化语句
     	performanceInterceptor.setFormat(true);
     	return interceptor;
     }
    
  • 在application.yml中配置

    profiles:
        active: dev #设置当前环境为dev
    

6、条件构造器(wapper)

官方介绍:条件构造器 | MyBatis-Plus (baomidou.com)
在这里插入图片描述

wrapper使用

  • 查询

    @Test
    public void testSelect(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Tom") //名字等于Tom
                .isNotNull("email") //email不等于空
                .between("age",10,30); //年龄在10到30之间
        List<User> list = userMapper.selectList(wrapper);
        list.forEach(System.out::println);
        
        Integer count = userMapper.selectCount(wrapper); //查询数量
        System.out.println(count);
        
        //模糊查询 .likeLeft() %在左边 .likeRight() %在右边
        QueryWrapper<User> wrapper1 = new QueryWrapper<>();
        wrapper1.notLike("name","e")
            .like("name","o")
            .likeRight("email","t"); //t% 邮箱号以t开头
        List<User> list1 = userMapper.selectList(wrapper1);
        list1.forEach(System.out::println);
        
        //排序
        QueryWrapper<User> wrapper2 = new QueryWrapper<>();
        wrapper2.orderByDesc("id");
        List<User> list2 = userMapper.selectList(wrapper2);
        list2.forEach(System.out::println);
        
        //分组 查询每一组的数量
        QueryWrapper<User> wrapper4 = new QueryWrapper<>();
        wrapper4.groupBy("age")
            .select("count(*) as num");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper4);
        maps.forEach(System.out::println);
    }
    
  • 子查询

    @Test
    public void testSelect(){
        //子查询
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.inSql("id","select id from user where id <4");
        List<User> list = userMapper.selectList(wrapper);
        list.forEach(System.out::println);
    }
    
  • or 和 and

    QueryWrapper<User> userWrapper = new QueryWrapper<User>();
    userWrapper.eq("name", name); //条件1
    userWrapper.and(wrapper -> wrapper.eq("pwd", pwd).or().eq("phone", phone));//条件2
    

    等同于:

    select * from user where name = ? and ( pwd= ? or phone = ?)
    

7、代码自动生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

  • 添加 代码生成器 依赖

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.4.1</version>
    </dependency>
    
  • 添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。

    • Velocity(默认):

      <dependency>
          <groupId>org.apache.velocity</groupId>
          <artifactId>velocity-engine-core</artifactId>
          <version>2.3</version>
      </dependency>
      
    • Freemarker:

      <dependency>
          <groupId>org.freemarker</groupId>
          <artifactId>freemarker</artifactId>
          <version>2.3.31</version>
      </dependency>
      
    • Beetl:

      <dependency>
          <groupId>com.ibeetl</groupId>
          <artifactId>beetl</artifactId>
          <version>3.3.2.RELEASE</version>
      </dependency>
      

      注意!如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。

  • 代码自动生成器

package com.lbb.mybatis_plus_demo;

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 Mycode {
    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("lbb"); //设置作者
        gc.setOpen(false); //是否打开资源管理器
        gc.setFileOverride(false); // 是否覆盖原来生成的
        gc.setServiceName("%sService"); // 去Service的I前缀
        gc.setIdType(IdType.AUTO);  //主键生成策略 这里是默认递增
        gc.setDateType(DateType.ONLY_DATE); //日期时间
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);
        //2、设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver"); //驱动
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        //3、包的配置
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName("blog");//模块名
        pc.setParent("com.lbb.mybatis_plus_demo"); //设置包名
        pc.setEntity("pojo"); //设置实体类包名
        pc.setMapper("mapper");//设置mapper包名
        pc.setService("service");//设置service包名
        pc.setController("controller");//设置controller包名
        mpg.setPackageInfo(pc);
        //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("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        // 乐观锁
        strategy.setVersionFieldName("version"); //乐观锁
        strategy.setRestControllerStyle(true); //驼峰命名Rest风格
        strategy.setControllerMappingHyphenStyle(true); //将localhost:8080/hello/id/2转化为 localhost:8080/hello_id_2样式
        mpg.setStrategy(strategy);

        mpg.execute(); //执行
    }
}

注意:如果开启Swagger 要添加依赖

<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

配置好路径,运行即可!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值