zoukankan      html  css  js  c++  java
  • MybatisPlus

    官网快速开始-:

    https://mp.baomidou.com/guide/quick-start.html#%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8

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

    使用了mybatis-plus 之后

    pojo
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    
    private Long id;
    private String name;
    private Integer age;
    private String email;
    }
    mapper接口
    
    // 在对应的Mapper上面继承基本的接口 BaseMapper
    @Repository // 代表持久层
    public interface UserMapper extends BaseMapper<User> {
    // 所有的CRUD操作都已经基本完成了
    // 你不需要像以前的配置一大堆文件了
    }

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

     没有写任何CRUD就已经有了这些方法,就是因为我们继承了父类BaseMapper

    public interface UserMapper extends BaseMapper<User>

    或者另一个项目的@MapperScan(basePackages = {"com.dao"}),只是命名时候mapper改成了dao而已

     配置日志

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

    # 配置日志 (系统自带的,控制台输出)
    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

    CRUD

    1. 插入操作

    @Test
    public void testInsert() {
        User user = new User();
        user.setName("Dainel");
        user.setAge(3);
        user.setEmail("daniel@alibaba.com");
    
        int result = userMapper.insert(user);// 帮我们自动生成id
        System.out.println(result);// 受影响的行数
        System.out.println(user);// 发现: id自动回填
    }

    上面的代码我们没有设置 User的id属性,但是插入的时候一样成功,因为mybatisplus会自动伴我们生成一个全局唯一id

    2. 主键生成策略

    数据库插入的id默认值为:全局的唯一id 这里面id的生成方式有很多比如如下的雪花算法

    雪花算法:

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

    主键自增

    我们需要配置主键自增:

    实体类字段上 @TableId(type = IdType.AUTO)

    数据库字段上一定是自增的,其实可以点开源码看看IdType的具体参数类型,都是可以选择的主键策略

    3. 更新操作

    //测试更新
    @Test
    public void testUpdate(){
        User user = new User();
        // 通过条件自动拼接动态sql
        user.setId(6L);
        user.setName("关注公众号");// 注意: updateById 但是参数是一个 对象
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

    //测试更新
    @Test
    public void testUpdate(){
        User user = new User();
        // 通过条件自动拼接动态sql
        user.setId(6L);
        user.setName("关注公众号");
        user.setAge(18);
        // 注意: updateById 但是参数是一个 对象
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

    来看一下两个不同的更新测试

    所有的sql都是自动帮你动态配置的!

    4. 自动填充

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

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

    方式一:数据库级别(工作中不允许修改数据库)

     方式二:代码级别

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

     2实体类的字段属性上需要增加注解

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

     3编写处理器来处理这个注解即可(当然这里官网也有  点击官网的自动填充https://mp.baomidou.com/guide/auto-fill-metainfo.html

    package com.kuang.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 java.util.Date;
    
    @Slf4j
    @Component // 一定不要忘记把处理器加到IOC容器中
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
        // 插入时候的填充策略
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ...");
            // 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("start update fill ...");
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    
    }

    5. 乐观锁

    在面试过程中,我们经常会被问到乐观锁,悲观锁。

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

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

    乐观锁实现方式:

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

    在mybatisPlus官网里也给我们写了乐观锁插件https://mp.baomidou.com/guide/interceptor-optimistic-locker.html#optimisticlockerinnerinterceptor

     1 数据库中增加一个version字段

     

     2 需要实体类加上对应的字段

     3 注册组件(官网有的)

    // 扫描我们的 mapper文件夹
    @MapperScan("com.kuang.mapper")
    @EnableTransactionManagement
    @Configuration
    public class MyBatisPlusConfig {
    
        // 注册乐观锁插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }

     4 测试一下成功与失败

     // 测试乐观锁成功
        @Test
        public void testVersionSuccess(){
            // 1. 查询用户信息
            User user = userMapper.selectById(1L);
            // 2. 修改用户信息
            user.setName("fan");
            user.setAge(24);
            // 3. 执行更新操作
            userMapper.updateById(user);
        }

    会发现执行的时候自动带上了version操作

     失败的情况模拟:

    两个用户都要去修改update操作,但是第一个操作后我们的version就改变了比如加一变成3了 

    所以都发现变成了3,那么后面的插入111那个邮箱就会失败,所以最后结果如下图为222

    6. 查询操作

    // 测试查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1);
        System.out.println(user);
    }
    
    // 批量查询
    @Test
    public void testSelectByBatchIds(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }
    
    // 按照条件查询之一使用 map
    @Test
    public void testSelectByMap(){
        HashMap<String, Object> map = new HashMap<>();
        // 自定义要查询
        map.put("name","Dainel");
        map.put("age","6");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

    7. 分页查询(重点,网站使用最多)

    分页网站频繁使用

    1. 原始使用limit进行分页
    2. pageHelper第三方插件
    3. MybatisPlus内置了分页插件

    如何使用MybatisPlus内置了分页插件,首先查看官网https://mp.baomidou.com/guide/page.html

    发现官网都是使用拦截器去配置的 ,我们复制官网先。

    1 配置拦截器

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

    2 直接使用Page对象即可

    首先我们查看提高的父类方法,里面有的方法就是带分页的如

    里面有两个参数,比如ipage接口,而ipage接口下面也有实现类如page我们直接实现即可,需要一个page我们new一个即可,如下。

    // 测试分页查询
    @Test
    public void testPage(){
        // 参数一: 当前页
        // 参数二: 页面大小
        // 使用了分页插件之后,所有的分页操作变得简单了
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page, null);
    
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }

    8. 删除操作

    // 测试删除
    @Test
    public void testdelete(){
        userMapper.deleteById(6L);
    }
    
    // 测试批量删除
    @Test
    public void testdeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(1287326823914405893L,1287326823914405894L));
    }
    
    //通过map删除
    @Test
    public void testDeleteByMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","KUANG");
        userMapper.deleteByMap(map);
    }

    9. 逻辑删除

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

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

    如:管理员可以查看被删除的记录!防止数据的丢失!类似于回收站!因为丢入回收站我们其实还可以看到,并还在

    测试:

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

    2.  实体类中增加属性

    3. 配置!然后就能看到那些被删了

     4测试删除

    发现日志里提示走的是更新操作

     

     

     5测试查询

    我们再看看逻辑删除后还能不能查询到刚刚逻辑删除的数据

    四、性能分析插件

    来自官网

    我们在平时的开发中,会遇到一些慢sql。解决方案:测试,druid监控…

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

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

    1导入插件(先要在SpringBoot中配置环境为dev或者test环境!)

    // SQL执行效率插件
    @Bean
    @Profile({"dev","test"})
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); //ms 设置sql执行的最大时间,如果超过了则不执行
        performanceInterceptor.setFormat(true); // 是否格式化
        return performanceInterceptor;
    }

    2测试使用

    // 测试查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(3);
        System.out.println(user);
    }

    就可显示时间,超过就会报错  30没有超过我们设置的100 所以正常运行

    五、条件构造器

    十分重要:wrapper  官网:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

    我们写一些复杂的sql就可以使用它来代替!需要什么官方看看,而我们就用官网的QueryWrapper父类试试

    其实就是运用wrapper的方法(还可以链式编程)

     再如:

      

     

    六、代码生成器

    dao、pojo、service、controller都给我自己去编写完成!

    官网:https://mp.baomidou.com/guide/generator.html

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

    MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:官网自己去看自己去找

     

     

     

     只需要更改表名即可自动生成代码

    最终结果如下

     同理

     这些类都会有了。

    下面的来自官网

        public static void main(String[] args) {
            // 代码生成器
            AutoGenerator mpg = new AutoGenerator();
    
            // 全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            gc.setOutputDir(projectPath + "/src/main/java");//输出目录
            gc.setAuthor("jobob");//作者
            gc.setOpen(false); //是否打开资源管理器
            // gc.setSwagger2(true); 实体属性 Swagger2 注解
            mpg.setGlobalConfig(gc);
    
            // 数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
            // dsc.setSchemaName("public");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("密码");
            mpg.setDataSource(dsc);
    
            // 包配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName(scanner("模块名"));
            pc.setParent("com.baomidou.ant");
            mpg.setPackageInfo(pc);
    
            // 自定义配置
            InjectionConfig cfg = new InjectionConfig() {
                @Override
                public void initMap() {
                    // to do nothing
                }
            };
    
            // 如果模板引擎是 freemarker
            String templatePath = "/templates/mapper.xml.ftl";
            // 如果模板引擎是 velocity
            // String templatePath = "/templates/mapper.xml.vm";
    
            // 自定义输出配置
            List<FileOutConfig> focList = new ArrayList<>();
            // 自定义配置会被优先输出
            focList.add(new FileOutConfig(templatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                            + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }
            });
            /*
            cfg.setFileCreate(new IFileCreate() {
                @Override
                public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                    // 判断自定义文件夹是否需要创建
                    checkDir("调用默认方法创建的目录,自定义目录用");
                    if (fileType == FileType.MAPPER) {
                        // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                        return !new File(filePath).exists();
                    }
                    // 允许生成模板文件
                    return true;
                }
            });
            */
            cfg.setFileOutConfigList(focList);
            mpg.setCfg(cfg);
    
            // 配置模板
            TemplateConfig templateConfig = new TemplateConfig();
    
            // 配置自定义输出模板
            //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
            // templateConfig.setEntity("templates/entity2.java");
            // templateConfig.setService();
            // templateConfig.setController();
    
            templateConfig.setXml(null);
            mpg.setTemplate(templateConfig);
    
            // 策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
            strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
            strategy.setEntityLombokModel(true);
            strategy.setRestControllerStyle(true);
            // 公共父类
            strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
            // 写于父类中的公共字段
            strategy.setSuperEntityColumns("id");
            strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(pc.getModuleName() + "_");
            mpg.setStrategy(strategy);
            mpg.setTemplateEngine(new FreemarkerTemplateEngine());
            mpg.execute();
        }
    
    }
  • 相关阅读:
    ZENCART 在文本格式郵件中轉換貨币符号
    ZENCART contact us 收不到邮件的问题
    zencart 如何修改在线人数和订单编号
    19.Oracle的动态监听和静态监听
    16.查看ORACLE的SAG和PGA的使用率
    1.Rman备份的基本命令
    4.ASM常用命令汇总
    2.Rman 备份、检查、维护、恢复
    2.oracle的备份和恢复之expdp和impdp命令02
    17.sqlnet.ora文件
  • 原文地址:https://www.cnblogs.com/yangj-Blog/p/14689106.html
Copyright © 2011-2022 走看看