“This is the second day of my participation in the First Challenge 2022.

This article mainly introduces mybatis-plus this plug-in for Springboot users. Including introduction, configuration, use, and extension of the common aspects of the summary, as far as possible to include the common scene content.

This article project code gitee address: gitee.com/wei_rong_xi…

About mybatis-plus is what, do not do more introduction, see the official document: baomidou.com/, we directly code up.

Start fast

This article is based on SpringBoot, Maven, JDK1.8, mysql development, so we need to prepare this environment before we start. My environment uses NACOS as the registry, do not know or need to build reference: Nacos 2.0 build and configure

Create the following database:

It is recommended that you choose utF8MB4 as the character set. Those of you who have done wechat will know that this character set is required to store the expressions of wechat user names.

I’ll assume that other environments are ready, so let’s just start with Mybatis – Plus.

1.1 Dependency Preparations

What dependency version would you like to see in maven repository: Maven repository address

Introducing mybatis- Plus dependencies:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>
Copy the code

Introduce mysql dependencies:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>
Copy the code

Currently, most projects require multiple data sources, or master/slave deployment, so we also need to introduce mybatis- Plus dependency on multiple data sources:

<! -- Mybatis -- Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>
Copy the code

1.2 Configuration Preparations

Springboot starts the class. Configure the @mapperscan annotation to scan Mapper file locations:

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@MapperScan("com.wjbgn.user.mapper")
@SpringBootApplication
public class RobNecessitiesUserApplication {

    public static void main(String[] args) { SpringApplication.run(RobNecessitiesUserApplication.class, args); }}Copy the code

Data source configuration, here configure a master and slave environment, currently I only have one, so the configuration is the same here:

spring:
  datasource:
    dynamic:
      primary: master Set the default data source or data source group to master
      strict: false If the specified data source is not matched, the default value is false
      datasource:
        master:
          url: JDBC: mysql: / / 127.0.0.1:3306 / rob_necessities? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
          username: root
          password: 123456
        slave_1:
          url: JDBC: mysql: / / 127.0.0.1:3306 / rob_necessities? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
          username: root
          password: 123456
Copy the code

1.3 Starting the Service

Start the service directly:

If the preceding information is displayed, the startup is successful.

Second, the use of

Before we successfully integrated mybatis-plus, with Springboot use is not too convenient. Let’s see how we can use it to manipulate our database. Introduce the general usage.

2.1 Entity class annotations

Mybatis – Plus encapsulates a lot of annotations for users, which is convenient for us to use. Let’s take a look at the annotations in the entity class first. There are the following entity classes:

@TableName(value = "user")
public class UserDO {

    /** * primary key */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /** ** nickname */
    @TableField("nickname")
    private String nickname;

    /** * Real name */
    private String realName;
}
Copy the code
  • @tablename TableName annotation, used to identify the table corresponding to the entity class.

    The instructions are as follows, and they are rarely used in the general case, without further explanation:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
    public @interface TableName {
    
        /** * the table name corresponding to the entity */
        String value(a) default "";
    
        /**
         * schema
         *
         * @since3.1.1 * /
        String schema(a) default "";
    
        /** * whether to use the global tablePrefix value * <p> only applies to both the global tablePrefix and the above {@link#value()} </p> * <li> If false, the global tablePrefix does not work </li> * *@since3.1.1 * /
        boolean keepGlobalPrefix(a) default false;
    
        /** * entity mapping result set, * only works with mp auto-injected method */
        String resultMap(a) default "";
    
        /** * Whether to automatically build and use a resultMap. * Only methods that are automatically injected with MP take effect. * If the resultMap is set, the resultMap will not be automatically built and injected. * Only applicable when typeHandler or jdbcType is set for individual fields * *@since3.1.2 * /
        boolean autoResultMap(a) default false;
    
        /** * The attribute name to exclude **@since3.3.1 * /
        String[] excludeProperty() default {};
    }
    Copy the code
  • @tableID primary key annotation

    Take a look at the source code:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    public @interface TableId {
    
        /** * field value (hump naming method, this value can not be) */
        String value(a) default "";
    
        /** * primary key ID * {@link IdType}
         */
        IdType type(a) default IdType.NONE;
    }
    Copy the code

    Where IdType is important:

    The name of the describe
    AUTO The ID of the database is automatically added
    NONE This type is unset primary key.
    INPUT The ID is set by the user
    ASSIGN_ID Automatically allocates a primary key of type Number or String when the user passes it empty (Snowflake algorithm)
    ASSIGN_UUID A primary key of type String is automatically assigned when the user passes it empty
  • @tableFiled Indicates the id of a table field

    Here’s a look at its main commonly used properties:

    The name of the describe
    value Database field name
    condition fieldwhereEntity query comparison condition, passedSqlConditionSet up the

    If no condition is specified, the query is performed based on normal equality

    If set, follow the following rules:

    = “%s=#{%s}”;

    NOT_EQUAL = “%s<>#{%s}”;

    CONCAT(‘%%’,#{%s},’%%’);

    Oracle about fuzzy ORACLE_LIKE = “% s LIKE CONCAT (CONCAT (‘ % %, # {} % s), ‘% %’)”;

    Left blur: LIKE_LEFT = “%s LIKE CONCAT(‘%%’,#{%s})”;

    %s LIKE CONCAT(#{%s},’%%’);
    fill Automatic fill policy, passFieldFillSet up the

    Do not handle: FieldFill.DEFAULT

    Fill the field when you INSERT: FieldFill.INSERT

    Fill in the field when updating: fieldfill.update

    Fill the field when inserting or adding: FieldFill.INSERT_UPDATE

    As for the other attributes, I don’t recommend using them. The more you use them, the easier it is to mask them. It can be set by wapper query.

2.2 the CRUD

Mybatis – Plus encapsulates an interface for us to call directly. About the internal specific method, in the use of their own experience, here is not listed.

2.2.1 CRUD Service layer

We need to inherit the IService interface from the service interface we define:

import com.baomidou.mybatisplus.extension.service.IService;
import com.wjbgn.user.entity.UserDO;

/ * * *@description: User service interface *@author: weirx *@date: 2022/1/17 15:02 *@version: 3.0 * /
public interface IUserService extends IService<UserDO> {}Copy the code

We also inherit ServiceImpl from our interface implementation impl to implement our own interface:

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wjbgn.user.entity.UserDO;
import com.wjbgn.user.mapper.UserMapper;
import com.wjbgn.user.service.IUserService;

/ * * *@descriptionUser interface implementation *@author: weirx *@date: 2022/1/17 15:03 *@version: 3.0 * /
public class UserServiceImpl extends ServiceImpl<UserMapper.UserDO> implements IUserService {}Copy the code

So our

2.2.2 layer Mapper CRUD

Mybatis – Plus encapsulates the commonly used CRUD interface into the BaseMapper interface, which we just need to inherit from our own Mapper:

/ * * *@description: user mapper *@author: weirx *@date: 2022/1/17 14:55 *@version: 3.0 * /
@Mapper
public interface UserMapper extends BaseMapper<UserDO> {}Copy the code

2.3 the paging

Using paging calls requires adding the configuration of the paging plug-in:

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.wjbgn.*.mapper*")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(a) {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        returninterceptor; }}Copy the code

After the above configuration, we’ll just use the paging method.

2.4 Deleting Logical Configurations

In many cases, our system requires logical deletion to facilitate recovery and search for mistakenly deleted data.

Mybatis – Plus can be configured globally without the need for manual processing. It is valid for update and query operations and does not restrict new operations.

To my usual logic, deleting a field is usually defined as IS_delete, which in the case of an entity class is isDelete. In the configuration file, you can have the following configuration:

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDelete # delete entity field name (since 3.3.0)
      logic-delete-value: 1 # Logical deleted value (default: 1)
      logic-not-delete-value: 0 # Logical undeleted value (default: 0)
Copy the code

Or via the annotation @tablelogic

@TableLogic
private Integer isDelete;
Copy the code

2.5 General Enumeration Configuration

I believe all of you at the back end have experienced a situation, such as the gender field, where the value and name correspond to 1 male and 2 female respectively. This field is a numeric type in the database, and the front-end display is the name of the string. How many common implementations are there?

  • The database queries the SQL by case and returns the name, as Oracle used to do
  • The value returned by the database, iterated through the assignment, and then needed to determine whether the value was male or female.
  • Write the front end dead, return 1 is male, return 2 is female.

Either method has its drawbacks, so we can use the method provided by Mybatis – Plus. When we return to the front end:

  • Just get the enumeration and assign its name without having to judge again.
  • Return it directly to the front end and let the front end remove the enumeration name

So that no one has to write down the value.

Here’s how to do this:

  • Enumeration, implement IEnum interface:

    import com.baomidou.mybatisplus.annotation.IEnum;
    import com.fasterxml.jackson.annotation.JsonFormat;
    
    / * * *@description: Gender enumeration *@author: weirx *@date: 2022/1/17 for *@version: 3.0 * /
    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    public enum SexEnum implements IEnum<Integer> {
        MAN(1."Male"),
        WOMAN(2."Female");
        private Integer code;
        private String name;
    
        SexEnum(Integer code, String name) {
            this.code = code;
            this.name = name;
        }
    
        @Override
        public Integer getValue(a) {
            return code;
        }
    
        public String getName(a) {
            returnname; }}Copy the code

    The @jsonFormat annotation addresses the problem of showing only the constructor name in front of the enumeration class return.

  • Entity class gender field

    @TableName(value = "user")
    public class UserDO {
    
        /** * primary key */
        @TableId(value = "id", type = IdType.AUTO)
        private Long id;
    
        /** ** nickname */
        @TableField(value = "nickname",condition = SqlCondition.EQUAL)
        private String nickname;
    
        /** ** gender */
        @TableField(value = "sex")
        private SexEnum sex;
    
        /** * version */
        @TableField(value = "version",update = "%s+1")
        private Integer version;
    
        /** * time field, automatically add */
        @TableField(value = "create_time",fill = FieldFill.INSERT)
        private LocalDateTime createTime;
    }
    Copy the code
  • Enumeration of configuration file scanning

    mybatis-plus:
      # support wildcard * or; segmentation
      typeEnumsPackage: com.wjbgn.*.enums
    Copy the code
  • Defining a configuration file

    @Bean
    public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer(a) {
        return properties -> {
            GlobalConfig globalConfig = properties.getGlobalConfig();
            globalConfig.setBanner(false);
            MybatisConfiguration configuration = new MybatisConfiguration();
            configuration.setDefaultEnumTypeHandler(MybatisEnumTypeHandler.class);
            properties.setConfiguration(configuration);
        };
    }
    Copy the code
  • Serialized enumeration values are database values

    Here is the fastjson I use:

    • Global (added in the previous configuration file) :
     @Bean
     public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer(a) {
         // Serialize enumerated values for database store values
         FastJsonConfig config = new FastJsonConfig();
         config.setSerializerFeatures(SerializerFeature.WriteEnumUsingToString);
    
         return properties -> {
             GlobalConfig globalConfig = properties.getGlobalConfig();
             globalConfig.setBanner(false);
             MybatisConfiguration configuration = new MybatisConfiguration();
             configuration.setDefaultEnumTypeHandler(MybatisEnumTypeHandler.class);
             properties.setConfiguration(configuration);
         };
     }
    Copy the code
    • local
     @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)
     private SexEnum sex;
    Copy the code

2.6 Automatic Filling

Remember the @tablefeild annotation in the entity class mentioned earlier? There’s a property called fill, and you set the property with FieldFill, and that’s what you do for auto-fill.

public enum FieldFill {
    /** ** does not process */ by default
    DEFAULT,
    /** * Insert the padding field */
    INSERT,
    /** * Update the padding field */
    UPDATE,
    /** * Insert and update the fill field */
    INSERT_UPDATE
}
Copy the code

However, this can not be used directly. The following configuration needs to be added by implementing the interface provided by Mybatis – Plus:

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/** * description: enable auto fill function *@return:
 * @author: weirx
 * @time: * / 2022/1/17 17:00
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // Version 3.3.0(recommended)
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // Version 3.3.0(recommended)
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); }}Copy the code

The fields are as follows:

/** * time field, automatically add */
@TableField(value = "create_time",fill = FieldFill.INSERT)
private LocalDateTime createTime;
Copy the code

2.7 Multiple Data Sources

As mentioned earlier, mybatis- Plus supports more modes:

  • The Lord and from much
spring:
  datasource:
    dynamic:
      primary: master Set the default data source or data source group to master
      strict: false If the specified data source is not matched, the default value is false
      datasource:
        master_1:
        master_2:
        slave_1:
        slave_2:
        slave_3:
Copy the code
  • Multiple databases
spring:
  datasource:
    dynamic:
      primary: mysql Set the default data source or data source group to master
      strict: false If the specified data source is not matched, the default value is false
      datasource:
        mysql:
        oracle:
        postgresql:
        h2:
        sqlserver:
Copy the code
  • Hybrid configuration
spring:
  datasource:
    dynamic:
      primary: master Set the default data source or data source group to master
      strict: false If the specified data source is not matched, the default value is false
      datasource:
        master_1:
        slave_1:
        slave_2:
        oracle_1:
        oracle_2:
Copy the code

The above three ways, in addition to mixed configuration, I think all can appear.

  • @ DS annotations

Annotations can be made on a method or on a class, and there is the proximity principle:

@DS("slave_1")
public class UserServiceImpl extends ServiceImpl<UserMapper.UserDO> implements IUserService {


    @DS("salve_1")
    @Override
    public List<UserDO> getList(a) {
        return this.getList();
    }

    @DS("master")
    @Override
    public int saveUser(UserDO userDO) {
        boolean save = this.save(userDO);
        if (save){
            return 1;
        }else{
            return 0; }}}Copy the code

Three, test,

With the above configuration, it’s time to start the test validation phase.

Create a table:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nickname` varchar(255) NOT NULL COMMENT 'nickname',
  `sex` tinyint(1) NOT NULL COMMENT 'Sex, 1 boy, 2 girls',
  `create_time` datetime NOT NULL COMMENT 'Creation time',
  `is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Delete 1 yes, 0 no'.PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8mb4;
Copy the code

Controller:

/ * * *@description: User controller *@author: weirx *@date: 2022/1/17 "*@version: 3.0 * /
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    /** * description: adds *@return: boolean
     * @author: weirx
     * @time: 2022/1/17 19:11 * /
    @RequestMapping("/save")
    public boolean save(a) {
        UserDO userDO = new UserDO();
        userDO.setNickname("Big pretty");
        userDO.setSex(SexEnum.MAN);

        return userService.save(userDO);
    }

    /** * description: modify *@param nickname
     * @param id
     * @return: boolean
     * @author: weirx
     * @time: 2022/1/17 19:11 * /
    @RequestMapping("/update")
    public boolean update(@RequestParam String nickname,@RequestParam Long id) {
        UserDO userDO = new UserDO();
        userDO.setNickname(nickname);
        userDO.setId(id);
        return userService.updateById(userDO);
    }

    /** * description: delete *@param id
     * @return: boolean
     * @author: weirx
     * @time: 2022/1/17 19:11 * /
    @RequestMapping("/delete")
    public boolean delete(@RequestParam Long id) {
        UserDO userDO = new UserDO();
        userDO.setId(id);
        return userService.removeById(userDO);
    }

    /** * description: list *@return: java.util.List<com.wjbgn.user.entity.UserDO>
     * @author: weirx
     * @time: 2022/1/17 19:11 * /
    @RequestMapping("/list")
    public List<UserDO> list(a) {
        return userService.list();
    }

    /** * description: paged list *@param current
     * @param size
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page
     * @author: weirx
     * @time: 2022/1/17 19:11 * /
    @RequestMapping("/page")
    public Page page(@RequestParam int current,@RequestParam int size) {
        return userService.page(new Page<>(current,size), new QueryWrapper(newUserDO())); }}Copy the code

Note the above interface verification, the function has no problem, the integration is successful.

Mybatis – Plus automatic code generation There will be a special chapter to explain the integration of Mybatis – Plus-Generator + Velocity, which generates all the background code and front-end code with one click.

This article project code gitee address: gitee.com/wei_rong_xi…