Mybatis-Plus在工作中的使用

Mybatis-Plus在工作中的使用

现在一般项目使用的持久层都是Mybatis,而我们介绍的MybatisPlus就是Mybatis的增强版,在MybatisPlus的文档中就有描述:
mybatisPlus的定位

MybatisPlus把自己定位在了Mybatis最好的搭档,在工作中使用mybatisPlus确实简化了很多我们的CRUD操作( CRUD是指在做计算处理时的增加(Create)检索(Retrieve)更新(Update)和删除(Delete) 几个单词的首字母简写。CRUD主要被用在描述软件系统中数据库或者持久层的基本操作功能。 )

MybatisPlus依赖配置:
其实mybatisPlus的官方指南已经写的很明白了。

首先在StringBoot项目的POM.xml文件中引入Spring-start父工程

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/>
</parent>

接下来引入需要的依赖:
第一个是用于简化实体类的工具lombok

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
</dependency>

第二个是数据库的驱动mysql

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
</dependency>

第三个就是mybatisPlus的依赖

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.2</version>
</dependency>

导入依赖后,就可以使用mybatisPlus了,导入了mybatisPlus就不需要再次导入mybatis的依赖了

Mybatis使用方式:
从前我们使用mybatis的步骤为:
1.创建mapper接口,添加@Mapper注解
2.创建mapper.xml文件,与mapper接口进行绑定,在文件中编写具体的SQL,进行执行。
3.在SpringBoot的启动器上添加==@MapperScan==,使Spring可以扫描到mapper文件。

但是现在使用mybatisPlus,我们一些简单的SQL不需要写在mapper文件当中了,简化了mapper文件的内容,甚至可能不需要mapper.xml文件

MybatisPlus使用方式:
1.创建Entity实体类,使用注解与数据库字段进行关联。
2.创建mapper接口,添加@Mapper注解,继承BaseMapper接口,泛型为Entity实体类,这样就与实体类进行关联。
3.在SpringBoot的启动器上添加==@MapperScan==,使Spring可以扫描到mapper文件。
4.此时创建mapper接口对象,mybatisPlus就已经帮我们封装了一些常用的CRUD方法,此时我们还可以在Service层继承ServiceImpl直接调用mybatisPlus在serviceImpl中封装的方法。
5.在SpringBoot的启动器上添加==@MapperScan==,使Spring可以扫描到mapper文件。

这就是创建的Entity实体类
Entity文件
mapper接口文件:
mapper文件
当Service使用时:
Service使用方法


时间添加小窍门(工作中不允许进行数据库的操作):
在工作中我们设计表的时候,一定会有两个字段,一个是创建时间,一个是更新时间。
1.当我们希望创建的时候能够自动填写当前时间的时候,我们就在默认内容中添加表达式==current_timestamp ==默认添加当前时间戳。
添加当前时间戳

2.当我们希望每次更新的时候自动更新时间,我们就在字段上勾选根据当前时间戳更新。
更具当前时间戳更新
这种情况我们不在数据库中进行操作,那我们可以使用mybatisPlus在代码中进行操作。
针对字段进行设置,我们使用==@TableField注解对字段进行设置。
1.设置注解
我们需要在
@TableField注解添加fill属性==,表明字段在添加时进行操作还是更新时进行操作还是两种情况都要进行操作
2.编写处理器来进行处理
编写一个handle(处理器) 实现MetaObjectHandle,重写其中的两个方法,一个是插入时的方法,一个是更新时的方法。下图为mybatisPlus的介绍文档中的处理器使用,如果想要在更新或插入时自动修改字段值,我们要使用该方法(setFieldValueByName方法已过时)。
处理器的模板


乐观锁与悲观锁
乐观锁:就是认为操作不会出现失误,每次操作都会成功,所以不会上锁。

悲观锁:就是认为每次操作都会出现失误,每次操作都会上锁。

乐观锁在操作时就是添加version版本字段,每次插入时都会校验上一次的version版本,如果版本符合,则更新操作,顺便version变为version+1,用于多线程的时候。

在mybatisPlus中有专门注解用于乐观锁==@Version==
首先我们要在创建一个config文件,将 @MapperScan 交给mybatisPlus的config文件扫描, @EnableTransactionManagement 用于开启事务, @Configuration 表明为配置类。

    /**
     * 注册乐观锁插件
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

完成配置。

只有执行updateByIdupdate方法时生效。会先查询此条数据,然后进行更新


查询:
我们可以直接通过mybatisPlus封装的方法进行查询,也可以创建Map集合(Map集合仅可以进行等于查询),集合Key为字段名value为条件。使用selectByMap()方法,可以根据条件进行查询


分页查询:
分页查询也需要配置一个拦截器。与乐观锁配置在同一个文件中
分页查询配置类
mybatisPlus中有两个页面的变量,一个是Page一个是IPage,两者的关系为Page实现了IPageIPage为接口Page为实体类,在工作中可能有互相调用的关系,在Feign接口中,是不能用IPage接收的,因为接口无法被实例化需要使用Page接收

Service文件:

        //获取查询条件
        QueryWrapper<user> queryWrapper = getQueryWrapper(pageQueryDto.getParams());
        //创建IPage对象 user为PO对象
        IPage<user> page = new Page<>(pageQueryDto.getPageNum(), pageQueryDto.getPageSize());
        //调用分页查询方法
        page = page(page, queryWrapper);

当我们查询的逻辑比较复杂时,就不能使用mybatisPlus自带的分页查询了,我们还是需要在mapper.xml中进行sql的编写,但是此时我们可以使用QueryWrapper对象构建条件。

mapper接口文件:
IPage对象与queryWrapper对象传入wrapper对象的写法为固定模式,修改后不生效

    List<user> selectToPage(IPage<user> page, @Param("ew") Wrapper<user> inDto);

mapper.xml文件:
由于wrapper为条件的集合,则在xml文件中使用此表达式,就可以自动拼接上查询条件。

SELECT id, name, age FROM user ${ew.customSqlSegment}

逻辑删除:
在工作中删除一般为逻辑删除,意思就是不会真正的在数据库进行删除,而是通过一种方式表明此条数据为作废数据。
mybatisPlus文档这这么描述的:
逻辑删除
我学习的视频中还说需要添加(不知道是否有用,如有需要则添加)

    /**
     * 注册逻辑删除插件
     */
    @Bean
    public ISqlInjector sqlInjector () {
        return new LogicSqlInjector();
    }

条件构造器
在MybatisPlus中,条件构造器是很核心的内容,其实条件构造器就是一个对象。

        QueryWrapper<Entity实体类名> queryWrapper = getQueryWrapper(Entity实体类对象);

创建了这个对象后,我们可以使用很多的方法,进行条件的拼接,这些在mybatisPlus的文档中都有介绍。
条件构造器
那我们如何去使用呢?我举一个例子

queryWrapper.in("name", inDto.getList());

这个就是条件构造器的对象的方法,表示在name字段中in查询,如果name字段的值在list里面则显示相当于in(a, b, c),诸如此类的方法还有很多中。


自动代码生成器:

3.0.3版本以后,自动代码生成器就需要额外引入依赖了。
此时我们引入依赖。

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.2</version>
</dependency>

还需要引入模板:

<!-- 默认模板-->
<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>

最后创建一个test类,然后编写代码生成器的配置就可以了
注意:如果需要自定义模板,则需要创建模板文件
模板文件


        //手动输入自己的包名
        String myPackage = "";
        //作者名
        String author = "";
        //表名
        String tableName = "";

        if (StringUtils.isNotEmpty(myPackage) && StringUtils.isNotEmpty(author) && StringUtils.isNotEmpty(tableName)) {
            // 1、创建代码生成器
            AutoGenerator mpg = new AutoGenerator();

            // 2、全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir"); //获取当前工程的src路径
            gc.setOutputDir(projectPath + "/src/main/java");
            gc.setAuthor(author); //作者
            gc.setOpen(false); //生成后是否打开资源管理器
            gc.setFileOverride(false); //重新生成时文件是否覆盖
            gc.setSwagger2(true);//开启Swagger2模式

            gc.setServiceName("%sService"); // 自定义Service模板 文件名
            mpg.setGlobalConfig(gc);


            // 3、数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("数据库地址");
            dsc.setDriverName("数据库连接");
            dsc.setUsername("用户名");
            dsc.setPassword("密码");
            dsc.setDbType(DbType.MYSQL);
            mpg.setDataSource(dsc);

            // 4、包配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName(null); //模块名
            pc.setParent("com.包名");
            pc.setController("controller." + myPackage);
            pc.setEntity("entity." + myPackage);
            pc.setService("service." + myPackage);
            pc.setMapper("mapper." + myPackage);
            mpg.setPackageInfo(pc);

            //5、自定义service模板(因项目中不需要serviceImpl层,所以自定义service模板)
            TemplateConfig templateConfig = new TemplateConfig();
            // 关闭原有生成
            templateConfig.setService(null);
            templateConfig.setServiceImpl(null);
            templateConfig.setMapper(null);
            templateConfig.setXml(null);
            templateConfig.setController(null);
            mpg.setTemplate(templateConfig);

            InjectionConfig cfg = new InjectionConfig() {
                @Override
                public void initMap() {
                    // to do nothing
                }
            };
            String serviceTemplatePath = "/templates/tempalteService.java.vm";
            // 自定义输出配置
            List<FileOutConfig> fileOutConfigList = new ArrayList<>();
            // 自定义Service模板 (如不需要就去掉)
            fileOutConfigList.add(new FileOutConfig(serviceTemplatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/java/com/包名/" + "service/" + myPackage + "/"
                            + tableInfo.getEntityName() + "Service" + StringPool.DOT_JAVA;
                }
            });
            String mapperTemplatePath = "/templates/tempalteMapper.java.vm";
            // 自定义Mapper接口模板 (如不需要就去掉)
            fileOutConfigList.add(new FileOutConfig(mapperTemplatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/java/com/包名/" + "mapper/" + myPackage + "/"
                            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_JAVA;
                }
            });
            String mapperXmlTemplatePath = "/templates/tempalteMapperXml.xml.vm";
            // 自定义XML文件模板 (如不需要就去掉)
            fileOutConfigList.add(new FileOutConfig(mapperXmlTemplatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/resources/" + "mapper/" + myPackage + "/"
                            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }
            });
            String controllerTemplatePath = "/templates/tempalteController.java.vm";
            // 自定义Controller文件模板 (如不需要就去掉)
            fileOutConfigList.add(new FileOutConfig(controllerTemplatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/java/com/包名/" + "controller/" + myPackage + "/"
                            + tableInfo.getEntityName() + "Controller" + StringPool.DOT_JAVA;
                }
            });
            cfg.setFileOutConfigList(fileOutConfigList);
            mpg.setCfg(cfg);

            // 6、策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setInclude(tableName);//表名
            strategy.setNaming(NamingStrategy.underline_to_camel);//下划线转驼峰
            if ("st_".equals(tableName.substring(0, 3))) {
                strategy.setTablePrefix("st_"); //生成实体时去掉表前缀
            }

            strategy.setColumnNaming(NamingStrategy.underline_to_camel);//下划线转驼峰
            strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

            strategy.setRestControllerStyle(true); //restful api风格控制器
            strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

            mpg.setStrategy(strategy);

            // 7、执行
            mpg.execute();
        }else {
            System.out.println("输入必填参数");
        }
    }

另一件事,如果需要分页查询,但是发现查询出来的total与实际数据不符,可以试试如下方法,关闭自动优化。

page.setOptimizeCountSql(false);

如果有需要自定义配置的小伙伴不会的也可以私聊我进行帮助哦!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值