Introduction and problems of mybatis-plus3. X

Time:2020-7-31

In my opinion, mybatis plus is an enhanced version of mybatis. It only adds functions to mybatis and does not make any changes to the original functions. It can be said that it is a very conscientious open source product. Today, I will give you a brief description of the following functions and the holes that have been stepped on.

preface

For those who don’t know much about the official website, you can watch this video at 2.0 speed, https://www.imooc.com/learn/1171 Video of mybatis plus from MOOC.

The latest version of 3. X stepped on several holes 2020 / 3 / 4 added

Mybatis plus provides a very powerful code generator, which can generate controller, service, mapper and mapping files with one click, eliminating many repeated actions. Here is the code of my simple encapsulated code generator. See the official website for more detailed configuration https://mp.baomidou.com/config/generator-config.html

package com.changda.flea.common.util;


import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @classname: CodeGenerator
 *@ Description: mybatisplus code generator
 *@ Author: South Street
 **/
public class CodeGenerator {

    /**
     *Configuration constants for code generator
     */
    Private static final string outputdir = "/ module name / SRC / main / Java";
    private static final String dataName = "xxxxx";
    private static final String dataPwd = "xxxx";
    private static final String dataUrl = "jdbc:mysql://localhost:3306/dbName?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8";
    private static final String driverName = "com.mysql.cj.jdbc.Driver";
    private static final String parentPackage = "com.changda.flea.common";
    private static final String mapperName = "dao";
    private static final String serviceName = "service";
    private static final String implName = "service.impl";
    private static final String pojoName = "entity";
    private static final String controllerName = "controller";
    private static final String xmlName = "mapper";
    //The current project path is used with outputdir, such as multi module development demo / test1, demo / test2
    //Projectpath gets the demo path. Set outputdir to / test1
    private static final String projectPath = System.getProperty("user.dir");

    public static void main(String[] args) {
        //Code generator
        AutoGenerator mpg = new AutoGenerator();

        //Global configuration
        GlobalConfig gc = getGlobalConfig();
        mpg.setGlobalConfig(gc);

        //Data source configuration
        DataSourceConfig dsc = getDataSourceConfig();
        mpg.setDataSource(dsc);

        //Package configuration
        PackageConfig pc = getPackageConfig();
        mpg.setPackageInfo(pc);

        InjectionConfig cfg = getInjectionConfig();
        mpg.setCfg(cfg);

        //Policy configuration
        StrategyConfig strategy = getStrategyConfig();
        mpg.setStrategy(strategy);
        mpg.execute();
    }


    /**
     *Global configuration
     *
     * @return
     */
    public static GlobalConfig getGlobalConfig() {
        return new GlobalConfig()
                .setOutputDir(projectPath + outPutDir)
                .setDateType(DateType.ONLY_DATE)
                .setAuthor("zhulin")
                .setOpen(false)
                .setBaseResultMap(true)
                .setBaseColumnList(true)
                //Override generated file
                .setFileOverride(true)
                .setServiceName("%sService");
    }

    /**
     *Data source configuration
     *
     * @return
     */
    public static DataSourceConfig getDataSourceConfig() {
        return new DataSourceConfig()
                .setUrl(dataUrl)
                .setDriverName(driverName)
                .setUsername(dataName)
                .setPassword(dataPwd);
    }

    /**
     *Package configuration
     *
     * @return
     */
    public static PackageConfig getPackageConfig() {
        return new PackageConfig()
                .setParent(parentPackage)
                .setMapper(mapperName)
                .setEntity(pojoName)
                .setService(serviceName)
                .setController(controllerName)
                .setServiceImpl(implName);
//                .setXml(xmlName);
    }

    /**
     *Policy configuration
     *
     * @return
     */
    public static StrategyConfig getStrategyConfig() {
        return new StrategyConfig()
                .setNaming(NamingStrategy.underline_to_camel)
                .setColumnNaming(NamingStrategy.underline_to_camel)
                .setEntityTableFieldAnnotationEnable(true)
                .setEntityLombokModel(true)
                . setinclude (scanner ("table name, separated by multiple commas"). Split (","))
                //All are generated by default
                //.setExclude(null)
                . settableprefix ("table prefix_ ""
                .setControllerMappingHyphenStyle(true);
    }

    /**
     *Custom XML file generation path
     *Notice that two XML will be generated, one is under the specified one, and the other is under the mapper package
     *It can't be solved for the time being, because the judgment in the source code is whether the XML properties of tableinfo and pathinfo are null. Both classes generate properties by default
     *And the judgment of if (null! = injectionconfig) custom generation is in front of the default, so it will be generated twice.
     *For details, see the method of abstracttemplateengine batchoutput()
     *
     * @return
     */
    public static InjectionConfig getInjectionConfig() {
        //Custom configuration
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {

            }
        };
        String templatePath = "/templates/mapper.xml.vm";
        //Custom output configuration
        List<FileOutConfig> focList = new ArrayList<>();
        //Custom configuration会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                //Custom output file name. If you set the Prefix suffix for entity, note that the name of XML will change accordingly!!
                Return projectpath + "/ module name / SRC / main / resources / mapper /"+ tableInfo.getEntityName () + "Mapper" +  StringPool.DOT_ XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    /**
     *Read console content
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println ("please enter" + tip + ":");
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        Throw new mybatisplusexception ("please enter the correct" + tip + "! "";
    }

}

It should be noted that lombox annotation is enabled for the entity class generated above, so if you use idea, you may also need to download a lombox plug-in and pom.xml Import the package of lombox into the file. Otherwise, you can close the package if you have trouble strategy.setEntityLombokModel (true); delete it. The default value is false;

As for the method of generating the service and mapper layers, let alone the official documents https://mp.baomidou.com/guide/crud-interface.html It will be more detailed

On pagination of mybtais-plus3. X

We know that before mybtais-plus 3. X, there was a paging plug-in (when paging, all data is queried, and then paging is performed through rowbounds)pagination。

However, the paging method before mybatis-plus3. X is like this, and it returns the list < T > set, and memory paging does not need to configure the paging plug-in

/**
     * <p>
     *Query all records (and turn pages) according to entity condition
     * </p>
     *
     *@ param rowbounds paging query criteria (can be RowBounds.DEFAULT )
     *The @ param wrapper entity object encapsulates the operation class (nullable)
     * @return List<T>
     */
    List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

But my pagination after using mybtais-plus3. X looks like this

/**
     *Page turning query
     *
     *@ param page paging object
     *@ param querywrapper entity object encapsulates operation class {@ link com.baomidou.mybatisplus . core.conditions.query .QueryWrapper}
     */
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);

We can see that the iPage interface is returned. In fact, the iPage returned here is the same as the first parameter page passed in. We can implement the iPage interface ourselves or use the provided iPage interface directly Pagehttps://mp.baomidou.com/guide/page.html

However, it should be noted here that if you want to use paging in version 3. X, you must configure the plug-in, otherwise it will have no effect. Unlike 2. X without plug-ins, it is memory paging.

package com.jianghaichao.infantmom.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @program: infantmom
 * @classname: MybatisPlusConfig
 *@ Description: mybatis plus configuration
 * @author: zhulin
 * @create: 2019-05-25 09:58
 **/
//Spring boot mode
@EnableTransactionManagement
@Configuration
@MapperScan("com.jianghaichao.infantmom.mapper")
public class MybatisPlusConfig {

    /**
     *Paging plug-in
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

The above is the configuration form of springboot

2. X’s entitywrapper to 3. X also becomes querywrapper

And lambda wrapper and others will not be listed one by one. Use it in understanding

On July 31, 2019, mybatis plus code generator generates localdatetime to query and report errors

The error report is as follows

org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column ‘created’ from result set.  Cause: java.sql.SQLFeatureNotSupportedException ; null; nested exception is java.sql.SQLFeatureNotSupportedException

resolvent:

Add a line to the code generator’s global policy gc.setDateType ( DateType.ONLY_ DATE);

Introduction and problems of mybatis-plus3. X

Setting the generated time type to date can solve the problem. This problem is also introduced on the official website

Introduction and problems of mybatis-plus3. X

Step on pit supplement on January 6, 2020, automatic filling of MP

We all know that, for example, the Alibaba development specification requires that each table should have a create_ Time and update_ Time field, so we often need to set the value of our own when inserting data and modifying data. Since this is the same operation, MP provides automatic injection. Here are some points to pay attention to when automatic filling.

See the official website for more usage https://mp.baomidou.com/guide/auto-fill-metainfo.html

1. Automatic injection will be triggered every time you insert or update. Therefore, we need to consider the performance problem. Then we will have the following optimized writing method. Here’s just an example of how to write insert. See the official website for more details

Introduction and problems of mybatis-plus3. X

It should be noted here that cretaetime is an entity class attribute rather than a database field name

The filling conditions are as follows:

Introduction and problems of mybatis-plus3. X

In addition, after version 3.3.0, the official recommendation is to use the strictinsertfill method. Here, we need to pay attention to the difference between insert and update

this.strictInsertFill (metaObject, "createTime",  LocalDateTime.class , LocalDateTime.now ()); // starting version 3.3.0 (recommended)
        this.fillStrategy (metaObject, "createTime",  LocalDateTime.now ()); // you can also use (3.3.0, this method has a bug, please upgrade to a later version, such as' 3.3.1.8-snapshot ')
        /*Choose one of the above, but the one below is out of date (note that strict insertfill has multiple methods. Check the source code for details)*/
        //this.setFieldValByName("operator", "Jerry", metaObject);
        //this.setInsertFieldValByName("operator", "Jerry", metaObject);

Step on the pit supplement on January 9, 2020, wrapper custom SQL

Recently, we encountered a problem with mybatis plus 3.2.0. From the official documents, we can see that this function has been available since 3.0.7

Introduction and problems of mybatis-plus3. XHere, I want to remind you that if you directly inject entity when instantiating, you will find that it is invalid. You must use EQ and other methods

//The following similar expressions are invalid
LambdaQueryWrapper<WxCommentVO> wrapper = Wrappers.lambdaQuery(wxComment);
QueryWrapper<WxCommentVO> wrapper1 = new QueryWrapper<>(wxComment);

//If you need to determine whether a field value is 1
wrapper.eq (wxcomment:: a field, 1);

It has to be written like this. It is invalid to inject directly through the entity class