• MybatisPlus


    Mybatis-Plus

    1、概述

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

    特性:

    • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
    • 损耗小:启动即会自动注入基本 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、Mybatist-Plus快速开始

    1、创建数据库

    现有一张 User 表,其表结构如下:

    id name age email
    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

    对应的sql语句

    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、创建一个Springboot的项目,导入依赖

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.0.5</version>
            </dependency>
    

    3、连接数据库

    #连接数据库
    spring.datasource.username=root
    spring.datasource.password=1234
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_puls?useSSL=false&useUnicode=true
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    

    4、编写user实体类、mapper接口、测试

    package com.hao.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private long id;
        private String name;
        private int age;
        private String email;
    }
    
    package com.hao.dao;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.hao.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;
    @Mapper
    @Repository
    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    @SpringBootTest
    class MybatisPulsApplicationTests {
        @Autowired
       private UserMapper userMapper;
        @Test
        void contextLoads() {
            List<User> userList = userMapper.selectList(null);
            for (User user : userList) {
                System.out.println(user);
            }
        }
    }
    

    在使用MybatisPlus开发后,无需写crud操作了,直接让Mapper直接继承BaseMapper接口,这里需要注意的是,BaseMapper后面的泛型,就是要操作的数据的返回类型。

    3、配置日志

    直接在application.properties文件中直接配置mybatisPlus的日志

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

    在使用日志后,能清楚的看到执行了哪条sql语句

    4、CRUD扩展

    4.1、插入操作

     @Test
        public void InsertTest(){
            User user = new User();
            user.setName("小胖学java");
            user.setAge(3);
            user.setEmail("1771742451@qq.com");
            int result = userMapper.insert(user);  //注意点:我们这里的User类没有给id主键赋值,BaseMapper中的insert方法会帮我们自动生成一个id
            System.out.println(result);
        }
    }
    

    4.1.1、主键生成策略

    系统默认type = IdType.ID_WORKER ,全局ID唯一

    分布式系统唯一id生成:主键生成策略

    雪花算法:

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

    其余的主键生成类型解释:

      /**
         * 数据库ID自增
         */
        AUTO(0),
        /**
         * 该类型为未设置主键类型
         */
        NONE(1),
        /**
         * 用户输入ID
         * 该类型可以通过自己注册自动填充插件进行填充
         */
        INPUT(2),
    
        /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
        /**
         * 全局唯一ID (idWorker)
         */
        ID_WORKER(3),
        /**
         * 全局唯一ID (UUID)
         */
        UUID(4),
        /**
         * 字符串全局唯一ID (idWorker 的字符串表示)
         */
        ID_WORKER_STR(5);
    

    4.2 、更新操作

     @Test
        public void UpdateTest(){
            User user = new User();
            user.setId(6L);
            user.setName("关注小胖博客:小胖学Java");
            userMapper.updateById(user);//这里方法名虽然为updateById,但参数类型是一个user类
        }
    

     @Test
        public void UpdateTest(){
            User user = new User();
            user.setId(6L);
            user.setAge(7);
            user.setName("关注小胖博客:小胖学Java");
            userMapper.updateById(user);
        }
    

    4.2.1、自动填充

    在我们插入和更新数据库表时,如果有记录时间的字段,也可以设置自动填充

    需要在user实体类上时间字段上添加注解:

    public class User {
        @TableId(type = IdType.ID_WORKER)
        private Long id;
        private String name;
        private Integer age;
        private String email;
        
        @TableField(fill = FieldFill.INSERT)
        private Date createtime;
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updatetime;
    }
    

    这里需要自己配置个组件:

    mybatisPlus版本为3.0.5,可以用这种方式实现

    @Slf4j
    @Component//记得把这个实现类交给ioc容器进行管理
    public class MyMetaObjectHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.setFieldValByName("createtime",new Date(),metaObject);
            this.setFieldValByName("updatetime",new Date(),metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.setFieldValByName("updatetime",new Date(),metaObject);
        }
    }
    
    

    版本不同的可以试试这个:

    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
            // 或者
            this.strictUpdateFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
            // 或者
            this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
            // 或者
            this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
            // 或者
            this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
        }
    }
    

    4.2.2、乐观锁

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

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

    乐观锁的实现机制:

    • 取出记录时,获取当前version
    • 更新时,带上这个version
    • 执行更新时,执行set version =new version where version=oldversion
    • 如果version不对,就更新失败
    乐观锁:先查询,过去版本号 version=1
    --A
    update user set name="xiaopang",version=version+1
    where id =2 and version =1;
    --B 如果线程B抢先完成,这个时候version=2,线程A再执行update就会失败了
    update user set name="xiaopang",version=version+1
    where id =2 and version=1
    
    

    测试:

    1、在数据库表中添加version字段

    2、在user实体类中添加相应的字段,并配上相应的乐观锁注解

      @Version
        private Integer version;
    

    3、编写乐观锁的组件配置

    @Configuration
    public class MyConfig {
        //乐观锁的插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor(){
             return new OptimisticLockerInterceptor();
        }
    }
    

    4、测试

    单线程下,成功的

    //测试单线程下,乐观锁成功案列
        @Test
        public void testOptimisticLockerInterceptor(){
            User user = userMapper.selectById(1L);
            user.setName("xiaopang");
            userMapper.updateById(user);
        }
    

    在多线程下,乐观锁的案列

     //多线程下,失败的案列
        @Test
        public void testOptimisticLockerInterceptor2(){
            //线程1
            User user = userMapper.selectById(1L);
            user.setName("xiaopang111");
            //线程2
            User user2 = userMapper.selectById(1L);
            user2.setName("xiaopang222");
            //假如让线程2执行了,线程1再执行更新就会失败了
            userMapper.updateById(user2);
            userMapper.updateById(user);
        }
    

    4.3、查询操作

      //按id查询,查询一个用户
        @Test
        public void testSelect(){
            User user = userMapper.selectById(2L);
            System.out.println(user);
        }
        //按id查询,查询多个用户
        @Test
        public void testSelectBatch(){
            ArrayList<Long> list = new ArrayList<Long>();
            list.add(1l);
            list.add(2l);
            list.add(3l);
            List<User> userList = userMapper.selectBatchIds(list);
            for (User user : userList) {
                System.out.println(user);
            }
        }
        //按多个条件查询用户
        @Test
        public void testSelectByMap(){
            HashMap<String,Object> map = new HashMap<>();
            map.put("name","xiaopang222");
            map.put("age","18");
            List<User> userList = userMapper.selectByMap(map);
            for (User user : userList) {
                System.out.println(user);
            }
        }
    

    4.3.1分页插件

    先配置mybatisPlus的分页插件组件即可

     //mybatisPlus分页插件
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
    //分页插件
        @Test
        public void testToPage(){
            Page<User> page = new Page<User>(2,3);//当前页面数,在第几页开始查询,页面的大小
            userMapper.selectPage(page, null);
            for (User user : page.getRecords()) {  //根据分页,查询的结果
                System.out.println(user);
            }
            System.out.println(page.getCurrent());  //当前所在的页面数
            System.out.println(page.getSize());  //总的页面数大小
            System.out.println(page.getPages());  //总的页面数
            System.out.println(page.getTotal()); //查询结果的总条数
        }
    

    4.4、删除操作

    4.4.1、逻辑删除

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

    逻辑删除:不会在数据库中直接移除,而是通过一个变量来让它失效 deletet=0 ==> deleted=1

    类似于回收站一样的,防止数据丢失。像浏览器的浏览记录一样,我们把它删除了,只是逻辑删除,管理员照样可以看的到记录的,嘿嘿嘿

    测试:

    1、在数据库表中添加deleted字段

    2、在实体类中添加相应的字段

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

    3、配置插件

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

    4、测试

    执行删除后的日志输出:

    然后再执行查询操作,查看刚刚删除的数据,看看是什么结果:

    5、性能分析插件

    我们在平时的开发中,会遇到一些慢的sql,这时候需要测试。

    作用:性能分析拦截器,用于输出每条sql语句及其执行的时间。

    1、导入插件

    @Bean
    @Profile({"dev","test"})
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor interceptor = new PerformanceInterceptor();
        interceptor.setFormat(true);//格式化执行的sql语句
        interceptor.setMaxTime(100);//设置sql最大的执行时间,默认单位为ms,如果超过了这时间,就会报错,不执行了
        return interceptor;
    }
    

    这里要注意开发环境

    #配置开发
    spring.profiles.active=dev
    

    2、测试使用

    6、条件查询器wapper

    我们写一些复杂的sql就可以使用wapper来代替了

    测试一:

    @Test
        void contextLoads() {
            //测试:名字不为空,email不为空,年龄大于24
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.isNotNull("name")
                    .isNotNull("email")
                    .ge("age","24");
            List<User> userList = userMapper.selectList(wrapper);
            for (User user : userList) {
                System.out.println(user);
            }
        }
    

    可以根据wapper写出不同的条件去执行,具体看Wapper条件器

    7、代码自动生成器

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

    package com.hao;
    
    import com.baomidou.mybatisplus.annotation.DbType;
    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;
    
    //代码生成器
    public class Creating {
        public static void main(String[] args) {
            //需要构建一个代码自动生成器 对象
            AutoGenerator generator = new AutoGenerator();
            //配置策略
            //1、全局配置
            GlobalConfig gc = new GlobalConfig();
            gc.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
            gc.setAuthor("小胖");
            gc.setOpen(false);
            gc.setFileOverride(false);//是否覆盖
            gc.setServiceName("%sService"); //去service前缀
            gc.setIdType(IdType.ID_WORKER);
            gc.setDateType(DateType.ONLY_DATE);
            gc.setSwagger2(true);
             generator.setGlobalConfig(gc);
             //2、设置数据源
            DataSourceConfig dsc = new DataSourceConfig();
               dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_puls?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false");
               dsc.setDriverName("com.mysql.cj.jdbc.Driver");
               dsc.setUsername("root");
               dsc.setPassword("1234");
               dsc.setDbType(DbType.MYSQL);
         generator.setDataSource(dsc);
         //3、包的配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName("blog");
            pc.setController("controller");
            pc.setEntity("pojo");
            pc.setMapper("mapper");
            pc.setService("service");
            pc.setParent("com.hao");
            generator.setPackageInfo(pc);
            //4、策略配置
            StrategyConfig sc = new StrategyConfig();
            sc.setInclude("blog"); //设置要映射的表名
            sc.setNaming(NamingStrategy.underline_to_camel);
            sc.setColumnNaming(NamingStrategy.underline_to_camel);
            sc.setEntityLombokModel(true);
    
              generator.setStrategy(sc);
            generator.execute();//执行
        }
    }
    

    这里要注意:生成的代码上附有一些注解,需要导入相应的依赖

         <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.7.0</version>
            </dependency>
            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.30</version>
            </dependency>
            <dependency>
                <groupId>com.ibeetl</groupId>
                <artifactId>beetl</artifactId>
                <version>3.2.4.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.apache.velocity</groupId>
                <artifactId>velocity-engine-core</artifactId>
                <version>2.0</version>
            </dependency>
            <dependency>
    

    效果如下:

  • 相关阅读:
    在CentOS-6.9里安装openvswitch-2.5.4
    Django 2.0.7 使用小知识
    微信小程序 存储数据到本地以及本地获取数据
    微信小程序目录结构与配置介绍
    微信小程序视图层介绍及用法
    小程序 wx.request请求
    小程序的启动流程(生命周期)
    小程序的双线程模型
    小程序之基础组件
    小程序之路由跳转
  • 原文地址:https://www.cnblogs.com/xiaopanjava/p/14082093.html
Copyright © 2020-2023  润新知