MENU

MybatisPlus快速入门

MybatisPlus快速入门

使用第三方组件:

1、导入对应的依赖

2、研究依赖是如何配置

3、代码的编写

4、提高扩展技术能力!

步骤
  1. 创建数据库mybatis_plus
  2. 创建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)
    );
    
    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(逻辑删除)、gmt_create、gmt_modified
  3. 编写项目。初始化项目!使用SpringBoot初始化
  4. 导入依赖

     <!--        数据库驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </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 版本差异!、

  5. 连接数据库 这一步和Mybatis相同!

    #mysql 5驱动不同 com.mysql.cj.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=juzi
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    #mysql 8 驱动不同com.mysql.cj.jdbc.Driver 需要增加时区配置 serverTimezone=GMT%2B8
  6. pojo -dao(之前需要 连接mybatis 配置mapper.xml)-service-controller

    使用了Mybatis-Plus 之后

    • pojo

      /**
       * @author: ZzRG
       * @version: 1.0
       * Date: 2022/6/27
       */
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class User {
      
          private Long id;
          private String name;
          private Integer age;
          private String email;
      
      }
    • mapper接口

      /**
       * @author: ZzRG
       * @version: 1.0
       * Date: 2022/6/27
       */
      
      //在对应的Mapper上面继承基本的接口 BaseMapper
      public interface UserMapper extends BaseMapper<User> {
      //    所有的curd 操作编写完成了
      //    不需要像以前那样写一大堆文件
      }
    • 注意点:我们需要在主启动器上去扫描 我们的Mapper包下的所有接口 @MapperScan("com.zzrg.xuexi.mapper")
    • 测试类中测试

      @SpringBootTest
      class MybatisPlusApplicationTests {
      
          //继承了BaserMapper的所有方法都来自父类, 我们也可以写自己的方法
          @Autowired
          private UserMapper userMapper;
      
          @Test
          void contextLoads() {
              //Wrapper<T>是一个参数 条件构造器  我们可以先不用设置为null
              //查询所有用户
              List<User> users = userMapper.selectList(null);
              users.forEach(System.out::println);
          }
      
      }
    • 使用

      image-20220627131249190

这里的关键所在

1、SQL谁帮我们写的? MyBatis-Plus都写好了

2、方法哪里来的? MyBatis-Plus 都写好了

配置日志

我们所有的sq|现在是不可见的,我们希望知道它是怎么执行的,所以我们必须要看日志!

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

image-20220627131809269

配置完日志之后,在学习时候就需要注意这个自动生成的SQL

CRUD扩展

自动插入

insert插入
    @Test
    public void testInsert(){
        User user = new User();
        user.setName("ZzRG");
        user.setAge(18);
        user.setEmail("123@qq.com");

        int insert = userMapper.insert(user);//帮我们自动生成id
        System.out.println(insert);//受影响的行数
        System.out.println(user);//发现id自动回填

    }

image-20220627143329471

数据库插入的id的默认值:全局的唯一id

主键生成策略

默认 ID_WORKER全局唯一id

分布式系统的唯一id生成:

雪花算发

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

主键自增:@TableId(type = IdType.AUTO)
  1. 我们需要配置主键自增
  2. 数据库字段一定要自增!

image-20220627144942659

与其他源码解释
public enum IdType{
    AUTO(0),//数据库id自增
    NONE(1),//未设置主键
    INPUT(2),//手动输入
    ID_WORKER(3),//默认的全局唯一id
    UUID(4),//全局唯一id uuid
    ID_WORKER_STR(5);// ID_WORKER 字符串表示法
}

更新操作

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(5L);
        //自动拼接动态sql
        user.setAge(15)
        user.setEmail("123456@qq.com");

        int update = userMapper.updateById(user);
        System.out.println(update);
        System.out.println(user);

    }

}

image-20220627145952919

注意:所有的sql都是自动动态配置!

自动填充

创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified 几乎所有的表都套配置上!且需要自动化!

方法一:数据库级别(工作中不允许使用)

1、在表中新增字段create_time,update_time

image-20220627151206378

2、再次测试插入方法,我们需要先把实体类同步

    private Date createTime;
    private Date updateTime;
方式二:代码级别

image-20220627152520027

    //字段填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    

编写处理器

package com.zzrg.xuexi.handler;

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

import javax.xml.crypto.Data;
import java.util.Date;

/**
 * @author: ZzRG
 * @version: 1.0
 * Date: 2022/6/27
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入...");
        //setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        this.setFieldValByName("createTime", new Date(),metaObject);
        this.setFieldValByName("updateTime", new Date(),metaObject);

    }
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新...");
        this.setFieldValByName("updateTime", new Date(),metaObject);

    }
}

插入测试

乐观锁

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

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

  • 我们这里主要讲解乐观锁机制!乐观锁实现方式:
  • 取出记录时,获取当前version·更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
乐观锁:1、查询,获取版本 version = 1
---线程A 
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
---线程B 抢先完成 这时候version = 2   线程A执行到的时候version不是1 然后会导致修改失败
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1

测试一下Mp的乐观锁插件

增加字段

image-20220627155405807

2、实体类上添加相应字段

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

3、注册插件

旧方法:

/**
 * @author: ZzRG
 * @version: 1.0
 * Date: 2022/6/27
 */
//扫描mapper文件夹
@MapperScan("com.zzrg.xuexi.mapper")
@EnableTransactionManagement
@Configuration//配置类
public class MybatisPlusConfig {
    //注册乐观锁插件 (老版)
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

新版

/**
 * @author: ZzRG
 * @version: 1.0
 * Date: 2022/6/27
 */
//扫描mapper文件夹
@MapperScan("com.zzrg.xuexi.mapper")
@Configuration//配置类
public class MybatisPlusConfig {
    //注册乐观锁插件
       /**
     * 新版
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

image-20220627160729072

@Test
public void testOptimisticLocker(){
    //查询用户信息
    User user = userMapper.selectById(1L);
    //修改信息
    user.setName("橘子");
    user.setEmail("110110@123.com");
    //执行更新
    userMapper.updateById(user);
}


@Test
public void testOptimisticLocker2(){
    //线程1
    //查询用户信息
    User user = userMapper.selectById(1L);
    user.setName("橘子");
    user.setEmail("110110@123.com");
    //线程2进行插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("橘子21");
    user2.setEmail("110110@123.com");
    userMapper.updateById(user2);

    //自旋锁多次尝试提交!
    userMapper.updateById(user);//没有乐观锁就会覆盖插队线程2的值
}

image-20220627162409625

查询操作

    //批量查询id
    @Test
    public void testSelectByBatchId(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }
    //条件查询Map
    @Test
    public void testSelectByBatchIds(){
        HashMap<String, Object> map = new HashMap<>();
        //自定义查询可以当多个条件
        map.put("name","ZzRG");
        map.put("id",1);
        map.put("age",3);
        
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

image-20220627163811576

分页查询

分页在网站上的使用

1、原始limit进行分页

2、pageHler分页插件

3、MybatisPlus内置分页

1、配置拦截器组件即可

@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
    //旧的
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}

2、直接使用Page对象即可

@Test
    public void selectPage(){
        //分页参数
        Page<User> pageParams = new Page<>(1,5);
        //执行分页
        userMapper.selectPage(pageParams,null);
        //查看分页参数成员
        System.out.println(pageParams);

    }

删除操作

    //测试删除
    @Test
    public void testDeleteById(){
        userMapper.deleteById(1L);
    }
    
    //批量删除
    @Test
    public void testDeleteBachId(){
        userMapper.deleteBatchIds(Arrays.asList(1L,2L,3L));
    }
    //通过map删除
    @Test
    public void testDeleteByMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id",1L);
        map.put("name","橘子");
        userMapper.deleteByMap (map);
    }

在工作会遇到逻辑删除的问题!

逻辑删除

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

逻辑删除:再数据库中没有被移除,而是通过一个变量来让他失效! deleted =0 => deleted = 1

管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!

1、在数据表中增加字段 :deleted

image-20220627170645929

2、实体类增加 属性

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

3、配置

    //逻辑删除的配置
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

image-20220627171627347

记录依旧在数据,但是值确实已经变化!

image-20220627171651508

执行查询语句!后面会自动拼接。

image-20220627172037459

性能分析插件

我们在平时的开发中,会遇到一些慢sql。测试! druid...

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

MP也提供性能分析插件,如果超过这个时间就停止运行!

1、导入插件

    /**
     * SQL执行效率
     * @return
     */
    @Bean
    @Profile({"dev","test"})//设置dev test 环境开启,保证效率
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();

        performanceInterceptor.setMaxTime(100);//ms 设置sql执行最大时间 如果超过则不执行
        performanceInterceptor.setFormat(true);//是否格式化
        return performanceInterceptor;
    }

配置环境

#设置开发环境
spring.profiles.active=dev

2、测试使用 只要超出设定最大时间就会抛出异常j!

image-20220627173703190

条件构造器

核心部分!!!

写一些复杂SQL的就可以用它代替!

Last Modified: July 9, 2022