zoukankan      html  css  js  c++  java
  • MyBatis-Plus入门及基本用法

    MyBatis-Plus入门及基本用法

    需要的基础:学习过MyBatis、Spring、SpringMVC就可以学习这个了!

    为什么需要学习它呢?MyBatis-Plus可以节约大量的工作时间,基本的CRUD可以自动化完成!

    JPA、tk-mapper、MyBatis-Plus

    简介

    是什么?MyBatis-Plus就是简化JDBC操作的!

    官网:https://mp.baomidou.com/ 简化MyBatis!

    image-20200813153822203

    特性

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

    快速入门

    地址:https://mp.baomidou.com/guide/quick-start.html#初始化工程

    使用第三方组件:

    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)
    );
    
    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>
    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!-- mybatis-plus为个人开发,并非官方的-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    

    说明:我们使用mybatis-plus可以节省我们大量的代码,尽量不要同时导入mybatis和mybatis-plus

    5、连接数据库,这一步和mybatis相同!

    #myql5 与mysql8驱动不同,同时mysql8需要增加时区的配置
    #mysql5为:com.mysql.jdbc.Driver,mysql8为:com.mysql.cj.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=123456qaz
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    

    传统方式:pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller

    6、使用mybatis-plus之后

    • pojo

      @Data
      //有参构造函数
      @AllArgsConstructor
      //无参构造函数
      @NoArgsConstructor
      public class User {
          private Long id;
          private String name;
          private int age;
          private String email;
      }
      
    • mapper接口

      package com.lin.mapper;
      
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.lin.pojo.User;
      import org.apache.ibatis.annotations.Mapper;
      import org.springframework.stereotype.Repository;
      
      //代表持久层
      @Repository
      @Mapper
      //在对应的Mapper上面继承基本的类BaseMapper
      public interface UserMapper extends BaseMapper<User> {
      }
      

    ​ 注意点:我们需要在主启动类上扫描我们的mapper包下的所有接口@MapperScan("com.lin.mapper")

    • 测试类中测试
    @SpringBootTest
    class MybatisPlusApplicationTests {
        //继承了BaseMapper,所有的方法都来自父类
        //可以编写自己的拓展方法
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void contextLoads() {
            //参数是一个wrapper,条件构造器,可以传null,查询全部用户
            List<User> users = userMapper.selectList(null);
            //第一种
            users.forEach(System.out::println);
            //第二种
            users.forEach(user -> System.out.println(user));
            //第三种
            for(User user : users) {
                System.out.println(user);
            }
        }
    }
    
    
    • 结果

      image-20200814142622068

    配置日志

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

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

    image-20200814150115433

    CRUD拓展

    插入操作

     @Test
        public void testInsert() {
            User user = new User();
            user.setName("林先生");
            user.setAge(12);
            user.setEmail("023023@qq.com");
            //帮我们自动生成id
            int insert = userMapper.insert(user);
            //受影响的行数
            System.out.println(insert);
            //自动回填id
            System.out.println(user);
        }
    

    image-20200814161731271

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

    主键生成策略

    默认 IdType.ID_WORKER 全局唯一id

    分布式系统唯一id生成参考博客:https://www.cnblogs.com/haoxinyue/p/5208136.html

    雪花算法:

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

    主键自增

    1. 实体类字段上 @TableId(type = IdType.AUTO)
    2. 数据库字段一定要自增

    其余的源码解释

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

    更新操作

    @Test
    public void testUpdate() {
        User user = new User();
        //通过条件自动拼接动态sql
        user.setAge(15);
        user.setName("和跳跳");
        user.setId(5L);
        //主义:updateByid 参数是一个对象
        userMapper.updateById(user);
    }
    

    image-20200814174018359

    所有的sql都是自动配置的!

    自动填充策略

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

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

    数据库级别(工作中一般不能修改数据库)

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

    alter table user add column create_time datetime not null default current_timestamp
    alter table user add column update_time datetime not null default current_timestamp on update current_timestamp;
    

    2、再次测试插入方法,再次之前需要同步实体类!

    private Date create_time;
    private Date update_time;
    

    3、测试结果如下:

    image-20200817105402995

    代码级别

    1、删除数据库的默认值及更新操作

    2、实体类属性上添加注解!

    @TableField(fill = FieldFill.INSERT)
    private Date create_time;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date update_time;
    

    3、编写处理器处理这个这个注解即可!

    package com.lin.handle;
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    import java.util.Date;
    
    @Slf4j//lombok的日志,也可以使用springboot自带的日志
    @Component//不要忘记把处理器加入到ioc容器中
    public class MyMetaObjectHandler implements MetaObjectHandler {
        //插入时的填充策略
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill...");
            this.setFieldValByName("create_time", new Date(),metaObject);
            this.setFieldValByName("update_time",new Date(),metaObject);
        }
    
        //更新时的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill...");
            this.setFieldValByName("update_time",new Date(),metaObject);
        }
    }
    

    4、结果如下:

    image-20200817114525169

    乐观锁

    在面试过程中,经常会被问到乐观锁以及悲观锁的机制。

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

    乐观锁实现方式:

    • 取出记录时,获取当前version
    • 更新时,带上这个version
    • 执行更新时, set version = newVersion where version = oldVersion
    • 如果version不对,就更新失败
    --A线程
    update user set name = ‘琳’ and version = version + 1
    where id = 2 and version = 1;
    
    --B线程抢先A线程完成更新操作,这个时候version = 2,导致A线程更新失败
    update user set name = ‘哈哈’ and version = version + 1
    where id = 2 and version = 1;
    

    测试MyBatis-Plus的乐观锁插件:

    1、给数据库加上version字段:

    alter table user add column version integer not null default 1 comment '版本号';
    

    image-20200817141256915

    2、实体类加对应的字段

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

    3、注册组件

    //不在启动类配置时,需要在此配置
    @MapperScan("com.lin.mapper")
    //默认开启事务管理
    @EnableTransactionManagement
    //集成第三方组件时需要添加此注解,表示配置类,@Bean搭配装配Bean
    @Configuration
    public class MyBatisPlusConfig {
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    

    4、测试:

    //测试乐观锁成功
    @Test
    public void testOptimisticLocker(){
        //查询
        User user = userMapper.selectById(4L);
        //修改
        user.setEmail("233823@qq.com");
        //更新
        userMapper.updateById(user);
    }
    
    //测试乐观锁失败
    @Test
    public void testOptimisticLocker2(){
        //模拟线程1
        User user = userMapper.selectById(4L);
        user.setEmail("233823@qq.com");
        //模拟线程2,线程2抢先更新操作
        User user1 = userMapper.selectById(4L);
        user1.setEmail("e9234823@qq.com");
        userMapper.updateById(user1);
        //线程1无法提交更新操作,如果没有乐观锁则会覆盖线程2提交的值
        //自旋锁多次尝试提交
        userMapper.updateById(user);
    }
    

    5、结果如下:

    image-20200817151900666

    查询操作

     //测试查询
        @Test
        public void testSelectById(){
            User user = userMapper.selectById(1L);
            System.out.println(user);
        }
    
        //测试批量查询
        @Test
        public void testSelectBatchById() {
            List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
            users.forEach(System.out::println);
        }
    
        //条件查询map
        @Test
        public void testSelectBatchByIds() {
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("name", "和跳跳");
            hashMap.put("age", 15);
            List<User> users = userMapper.selectByMap(hashMap);
        }
    

    分页查询

    • 原始的limit进行分页
    • PageHelper第三方插件
    • MyBatis-Plus也有内置插件

    1、配置拦截器组件

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        return paginationInterceptor;
    }
    

    2、直接使用page对象

    //测试分页查询
    @Test
    public void testPage() {
        //创建Page对象
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page, null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }
    

    image-20200817161351607

    删除操作

    基本的删除操作

    @Test
    public void testDeleteById() {
        userMapper.deleteById(1294183513728778242L);
    }
    
    @Test
    public void testDeleteBatchById() {
        userMapper.deleteBatchIds(Arrays.asList(1294183513728778243L,1294183513728778244L));
    }
    
    @Test
    public void tesetDeleteBatchByIds() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "林先生");
        userMapper.deleteByMap(map);
    }
    

    逻辑删除

    逻辑删除即不会删除数据库数据,对应数据的deleted = 0变成 deleted = 1状态的变化

    1、数据库添加字段deleted

    alter table user add column deleted integer not null default 0 comment '删除状态'
    

    2、实体类添加相应字段

    @TableLogic
    private Integer deleted;
    

    3、配置(3.1.1以上版本不需要配置)

    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
    

    properties如下:

    #已删除值为1
    mybatis-plus.global-config.db-config.logic-delete-value=1
    #未删除值为0
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
    

    4、测试结果如下:

    image-20200817171043799

    条件构造器

    //isNotNull、ge、between
    @Test
    public void testWrapper1() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.isNotNull("name").ge("age", 15).between("create_time", "2019-09-08 00:00:00", "2020-08-24 00:00:00");
        userMapper.selectList(userQueryWrapper).forEach(System.out::println);
    }
    
    //eq、lt
    @Test
    public void  testWrapper2() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("name", "琳姑姑").lt("age", 100);
        System.out.println(userMapper.selectOne(userQueryWrapper));
        System.out.println(userMapper.selectCount(userQueryWrapper));
    }
    
    //notLike、likeLeft
    @Test
    public void testWrapper3() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
        userQueryWrapper.notLike("name", "姑姑").likeLeft("name", "跳跳");
        List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
        maps.forEach(System.out::println);
    }
    
    //inSql
    @Test
    public void testWrapper4() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
        userQueryWrapper.inSql("id", "select id from user where id < 5");
        List<Object> objects = userMapper.selectObjs(userQueryWrapper);
        objects.forEach(System.out::println);
    }
    
    //orderBy
    @Test
    public void testWrapper5() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
       userQueryWrapper.orderByDesc("id").orderByAsc("age");
        List<Object> objects = userMapper.selectObjs(userQueryWrapper);
        objects.forEach(System.out::println);
    }
    

    代码自动生成器

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

    引入依赖:

    <!-- mybatis-plus代码生成器-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.3.2</version>
    </dependency>
    <!-- 模板引擎-->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.2</version>
    </dependency>
    

    编写生成器:

    package com.lin.config;
    
    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 MyBatisAutoGenerator {
        public static void main(String[] args) {
            //代码生成器
            AutoGenerator autoGenerator = new AutoGenerator();
    
            //全局配置
            GlobalConfig globalConfig = new GlobalConfig();
            globalConfig.setAuthor("LinXianSheng");
            //时间类型
            globalConfig.setDateType(DateType.ONLY_DATE);
            //ID增长
            globalConfig.setIdType(IdType.AUTO);
            //打开文件目录
            globalConfig.setOpen(false);
            //Swagger2
            globalConfig.setSwagger2(true);
            //是否覆盖原有文件
            globalConfig.setFileOverride(false);
            //文件输出目录
            String projectPath = System.getProperty("user.dir");
            globalConfig.setOutputDir(projectPath + "/src/main/java");
            autoGenerator.setGlobalConfig(globalConfig);
    
            //数据源配置
            DataSourceConfig dataSourceConfig = new DataSourceConfig();
            //数据库类型
            dataSourceConfig.setDbType(DbType.MYSQL);
            dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
            dataSourceConfig.setUsername("root");
            dataSourceConfig.setPassword("123456");
            //驱动名称
            dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
            autoGenerator.setDataSource(dataSourceConfig);
    
            //包配置
            PackageConfig packageConfig = new PackageConfig();
            packageConfig.setController("controller");
            packageConfig.setEntity("entity");
            packageConfig.setService("service");
            packageConfig.setMapper("mapper");
            packageConfig.setParent("com.lin");
            packageConfig.setModuleName("blog");
            autoGenerator.setPackageInfo(packageConfig);
    
            //策略配置
            StrategyConfig strategyConfig = new StrategyConfig();
            strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
            strategyConfig.setLogicDeleteFieldName("deleted");
            strategyConfig.setVersionFieldName("version");
            strategyConfig.setInclude("user");
            //生成@RestController
            strategyConfig.setRestControllerStyle(true);
            //生成lombok
            strategyConfig.setEntityLombokModel(true);
            //驼峰转连字符,localhost:8080/hello_id_10,即访问带下划线参数
            strategyConfig.setControllerMappingHyphenStyle(true);
            //自动填充设置
            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.setTableFillList(tableFills);
            autoGenerator.setStrategy(strategyConfig);
            //执行
            autoGenerator.execute();
        }
    }
    
    

    生成结果如下:

    image-20200818164118053

    自我控制是最强者的本能-萧伯纳
  • 相关阅读:
    nginx 配置https详细步骤
    Git 上传本地仓库到远程git仓库
    VUE 配置vscode关于vue插件
    ORA-01439:要更改数据类型,则要修改的列必须为空
    Oracle查看主键、删除主键、添加联合主键
    std::stoi, std::stol, std::stoll
    C+++string类如何判断字符串为空
    1day漏洞反推技巧实战(1)
    java反射笔记,自用
    tomcat Valve内存马
  • 原文地址:https://www.cnblogs.com/CF1314/p/13524432.html
Copyright © 2011-2022 走看看