[ crazy victory theory ] MybatisPlus notes sorting

Posted by MuseiKaze on Sun, 23 Jan 2022 18:10:17 +0100

MybatisPlus


MyBatis-Plus (opens new window) (MP) is a MyBatis (opens new window) On the basis of MyBatis, the enhancement tool is only enhanced without change. It is born to simplify development and improve efficiency.

characteristic

  • No invasion: it is only enhanced without change, and its introduction will not affect the existing project, which is as smooth as silk
  • Low loss: the basic CURD will be injected automatically upon startup, with basically no loss of performance and direct object-oriented operation
  • Powerful crud operation: built in general Mapper and general Service, most CRUD operations of a single table can be realized only through a small number of configurations, and there is a powerful condition constructor to meet various use requirements
  • Support Lambda formal call: it is convenient to write various query conditions through Lambda expression, and there is no need to worry about wrong fields
  • Support automatic generation of primary key: support up to 4 primary key strategies (including distributed unique ID generator - Sequence), which can be configured freely to perfectly solve the primary key problem
  • Support ActiveRecord mode: support ActiveRecord formal calls. Entity classes only need to inherit Model classes to perform powerful CRUD operations
  • Support custom global general operations: support global general method injection (Write once, use anywhere)
  • Built in code generator: code or Maven plug-in can be used to quickly generate Mapper, Model, Service and Controller layer code, support template engine, and have more custom configurations for you to use
  • Built in paging plug-in: Based on MyBatis physical paging, developers do not need to care about specific operations. After configuring the plug-in, writing paging is equivalent to ordinary List query
  • The paging plug-in supports multiple databases: MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer and other databases
  • Built in performance analysis plug-in: it can output SQL statements and their execution time. It is recommended to enable this function during development and testing to quickly find out slow queries
  • Built in global interception plug-in: it provides intelligent analysis and blocking of full table delete and update operations, and can also customize interception rules to prevent misoperation

Frame structure

Quick start

Quick start Quick start | mybatis plus (Baidu. Com)

step

1. Create database

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
    id BIGINT(20) NOT NULL COMMENT 'Primary key ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT 'full name',
    age INT(11) NULL DEFAULT NULL COMMENT 'Age',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT 'mailbox',
    PRIMARY KEY (id)
);
--In real development, version(Optimistic lock),daleted(Logical deletion),gmt_craete,gmt_modified
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. Initialize the project, create a new springboot project, and import dependencies

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

Note: we use mybatis -Plus can save us a lot of code. Try not to import mybatis and mybatis plus at the same time!

3. Connect to the database

#mysql5
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

4. POJO Dao (configure mapper. XML) - service controller

package com.example.mybatisplsh01.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
    private String email;
}

mapper layer

package com.example.mybatisplsh01.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplsh01.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

//Just implement the corresponding interface on the corresponding mapper
//Represents Dao layer
@Repository
public interface UserMapper extends BaseMapper<User> {
    //All CRUD are written
}

main program

package com.example.mybatisplsh01;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//Scan dao files
@MapperScan("com.example.mybatisplsh01.dao")
@SpringBootApplication
public class MybatisPlsh01Application {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlsh01Application.class, args);
    }

}

Note: we need to scan all interfaces under our mapper package on the main startup class

test

package com.example.mybatisplsh01;

import com.example.mybatisplsh01.dao.UserMapper;
import com.example.mybatisplsh01.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class MybatisPlsh01ApplicationTests {

    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
        //All methods come from the parent class, and we can also write extension methods
        //The parameter here is a mapper and a condition constructor. We don't need it here, but write it as null
        List<User> userList = userMapper.selectList(null);
        for (User user : userList) {
            System.out.println(user);
        }
    }

}

Configuration log

All our sqld is invisible now. We want to know how it is executed, so we must look at the log!

## Configuration log ##Default console output
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl 

After configuring the log, you need to pay attention to the automatically generated sql in later learning

CRUD extension

Insert operation

Insert insert

  @Test
    void insert(){
        User user = new User();
        user.setAge(3);
        user.setName("xiaoqi");
        user.setEmail("123456");
        int insert = userMapper.insert(user);
        System.out.println(insert);
        System.out.println(user);
    }

The default value of the database insert id is the global unique id

Primary key generation strategy

Default ID_WORKER globally unique id

Generation of unique id of distributed system: https://www.cnblogs.com/haoxinyue/p/5208136.html

Snowflake algorithm:

snowflake is Twitter's open source distributed ID generation algorithm, and the result is a long ID. Its core idea is to use 41bit as the number of milliseconds, 10bit as the machine ID (five bits are the data center and five bit machine ID), 12bit as the serial number within milliseconds (meaning that each node can generate 4096 IDS per millisecond), and finally there is a symbol bit, which is always 0. Can guarantee almost the only one in the world!

Primary key auto increment:

We need to configure primary key auto increment:

  1. @ TableId(type = IdType.AUTO) on entity class field
  2. The database fields must be self incremented

The self incrementing id is set in java, and the database needs to be synchronized, otherwise an error will be reported

problem

If there is a row with id 0 in the database, you need to set the id of this row to a number greater than 0, and then click auto increment.

Other codes

public enum IdType {
    /**
     * Database ID self increment
     * This type is invalid if ID self increment is set in the database
     */
    AUTO(0),
    /**
     * This type is not set with primary key (in the annotation, it is equal to follow the global, and the global value is equal to INPUT)
     */
    NONE(1),
    /**
     * User input ID
     * This type can be filled by registering the auto fill plug-in
     */
    INPUT(2),

    /* The following three types are automatically filled only when the inserted object ID is empty. */
    /**
     * Assign ID (the primary key type is number or string),
     * Default implementation class {@ link com. Baomidou. Mybatisplus. Core. Increment. Defaultidentifier generator} (snowflake algorithm)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * Assign UUID (the primary key type is string)
     * Default implementation class {@ link com. Baomidou. Mybatisplus. Core. Increment. Defaultidentifiergenerator} (UUID. Replace ("-", ""))
     */
    ASSIGN_UUID(4);

update operation

Although it is byid, the updated is user

    @Test
    void update(){
        //Automatic splicing dynamic sql
        User user = new User();
        user.setAge(3);
        user.setId(6);
        user.setName("xx");
        user.setEmail("123456");
        //A parameter is an object
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

Auto fill

Creation time and modification time! These operations are generally completed automatically. We don't want to update them manually!

Alibaba Development Manual: all database tables: gmt_create,gmt_modified almost all tables should be configured! And need automation!

Method 1: database level (database modification is not allowed during work)

1. Add a new field in the table: create_ time update_ time

2. To test the insertion method again, we need to synchronize in the entity class

    private Date createTime;
    private Date updateTime;

Method 2: code level

1. Delete the default value of the database

2. Add annotation on the field attribute of entity class

    //Field fill content
    @TableField(fill = FieldFill.INSERT)
    private Date createrTime;
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;

3. Write the processor to process this annotation

package com.example.mybatisplsh01.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;

@Component //Add components to IOC container
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        //Population policy at insertion
        log.info("start instert fill");
        this.setFieldValByName("createTime",new Date(), metaObject);
        this.setFieldValByName("updateTime",new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        //Population policy when updating
        log.info("start update");
        this.setFieldValByName("updateTime",new Date(),metaObject);

    }
}

4. Test insertion and update

Optimistic lock

During the interview, we are often asked about optimistic lock and pessimistic lock.

Optimistic lock: as the name suggests, it always thinks that there will be no problem. No matter what you do, you don't lock it! If there is a problem, update the value test again!

Pessimistic lock: as the name suggests, it always thinks that there is always a problem and locks everything! Do it again!

Optimistic lock implementation method:

  • When fetching records, get the current version
  • When updating, bring this version
  • When updating, set version = newVersion where version = oldVersion
  • If the version is incorrect, the update fails

Test the optimistic lock plug-in of mybatisplus

1. Add the version field to the database and set the default value to 1

2. Add field in entity class

    @Version //Optimistic lock annotation
    private Integer version;

3. Register components

package com.example.mybatisplsh01.config;

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

//Mybatis plus is managed here
//Scan dao files for components to take effect
@MapperScan("com.example.mybatisplsh01.dao")
@EnableTransactionManagement //Transaction start
@Configuration //Configuration class
public class MybatisPlusConfig {
    //Register optimistic lock plug-in
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

4. Test

 @Test
    //Test optimistic lock
    void testOpt(){
        User user = userMapper.selectById(1);
        //Modify user information
        user.setName("xxxx");
        user.setEmail("78952");
        userMapper.updateById(user);
    }

Failure example, simulate thread queue jumping

    @Test
    //Test optimistic lock
    void testOpt(){
        //Thread 1
        User user = userMapper.selectById(1);
        //Modify user information
        user.setName("xxxx");
        user.setEmail("78952");
        //Simulate another thread to perform queue jumping
        User user2 = userMapper.selectById(1);
        //Modify user information
        user2.setName("xxxx2");
        user2.setEmail("78952");
        userMapper.updateById(user2);
        //Spin lock operation can be used
        userMapper.updateById(user); //If there is no optimistic lock, the value of the insert thread is overwritten
    }

Query operation

   @Test
    //Test query
    void testselect(){
        User user = userMapper.selectById(1);
        System.out.println(user);
    }

Batch query, using array tool class

    @Test
    //Test query
    void testselect(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }

Conditional query, using map

    @Test
    //Condition query
    void testSelectmap(){
        HashMap<String, Object> map = new HashMap<>();
        //Customize the conditions to query
        map.put("name","xx");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);

    }

Paging query

Paged websites are frequently used

  1. The original uses limit for paging
  2. pageHelper third party plug-in
  3. MybatisPlus has a built-in paging plug-in

How to use?

1. Configure interceptor

 /**
         * The new paging plug-in follows the rules of mybatis. MybatisConfiguration#useDeprecatedExecutor = false is required
         * Avoid cache problems (this attribute will be removed after the old plug-in is removed)
         */
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));

2. Test direct use

    @Test
    void limitpage(){
        //Parameter 1, current page, parameter 2, page size
        Page<User> page = new Page<>(2,5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
    }

Delete operation

Basic delete operation

    @Test
    void delete(){
        int deleteById = userMapper.deleteById(9);
        System.out.println(deleteById);
    }

    @Test
    void deletebatch(){
        userMapper.deleteBatchIds(Arrays.asList(6,7));
    }

    @Test
    void deleteMap(){
        HashMap<String,Object> map = new HashMap();
        map.put("name","xxxx2");
        userMapper.deleteByMap(map);
    }

Logical deletion

Physical delete: remove directly from the database

Logical deletion: it is not removed from the database, but made effective through a variable! deleted =0 => deleted = 1

Administrators can view deleted records to prevent data loss, similar to the recycle bin

Test:

1. Add a deleted field in the data table

2. Add attribute in entity class

@TableLogic //Logical deletion
private Integer deleted;

3. Configuration

# Global logically deleted entity field name (since 3.3.0, it can be ignored after configuration, and step 2 is not configured)
# Logical deleted value (default = 1)
# Logical undeleted value (0 by default)
mybatis-plus.global-config.db-config.logic-delete-field=flag
mybatis-plus.global-config.db-config.logic-delete-value=1 
mybatis-plus.global-config.db-config.logic-not-delete-value= 0 

The test performed for delete is an update operation, not a delete operation

In the database, the field deleted becomes 1, but the data is not deleted

Test query, the result is not found

The logically deleted fields will be automatically filtered during query

Performance analysis plug-in

In our usual development, we will encounter some slow sql. Solution: testing, druid monitoring

Function: performance analysis interceptor, used to output each SQL statement and its execution time

MyBatisPlus also provides a performance analysis plug-in. If it exceeds this time, it will stop running!

Conditional constructor

Very important: wrapper

We can use it instead of writing some complex sql!

test

package com.example.mybatisplsh01;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mybatisplsh01.dao.UserMapper;
import com.example.mybatisplsh01.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.management.Query;

@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads(){
        //Query parameters whose name and mailbox are not empty, and whose age is greater than or equal to 12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        userMapper.selectList(wrapper).forEach(System.out::println);
    }
}

 @Test
    void test2(){
        //The query name is a specific name
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Tom");
        System.out.println(userMapper.selectOne(wrapper));
    }

@Test
void test3(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",20,30);
    Long aLong = userMapper.selectCount(wrapper);
    System.out.println(aLong);
}

   @Test
    //Fuzzy query
    void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //Left and right% e%
        wrapper.notLike("name","e")
                //Right represents% on the right
                .likeRight("email","t");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

    @Test
    void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //Linked table query
        //You can find the id in this select statement
        wrapper.inSql("id","select id from user where id > 4");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }

    @Test
    void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //Sort by id
        wrapper.orderByDesc("id");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

official: Conditional constructor | mybatis plus (baomidou. Com)

Automatic code generator

dao, pojo, service and controller are all written by myself!

AutoGenerator is the code generator of mybatis plus, which can quickly generate Entity

The code of Mapper, Mapper XML, Service, Controller and other modules greatly improves the development efficiency.

You only need to change the entity class name, package name and database configuration

import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; 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.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; 

// Automatic code generator 
public class KuangCode {
public static void main(String[] args) {
    // You need to build an automatic code generator object 
    AutoGenerator mpg = new AutoGenerator(); 
    
    // Configuration policy 
    // 1. Global configuration 
    GlobalConfig gc = new GlobalConfig();
    String projectPath = System.getProperty("user.dir"); 
    gc.setOutputDir(projectPath+"/src/main/java");
    gc.setAuthor("Madness theory"); gc.setOpen(false);
    gc.setFileOverride(false);
    
    // Overwrite
    gc.setServiceName("%sService");
    
    // I prefix to Service
    gc.setIdType(IdType.ID_WORKER);
    gc.setDateType(DateType.ONLY_DATE);
    gc.setSwagger2(true);
    mpg.setGlobalConfig(gc);
    
    //2. Set data source
    DataSourceConfig dsc = new DataSourceConfig();
    dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
    dsc.setDriverName("com.mysql.cj.jdbc.Driver");
    dsc.setUsername("root");
    dsc.setPassword("123456");
    dsc.setDbType(DbType.MYSQL); 
    mpg.setDataSource(dsc);
    
    //3. Package configuration
    PackageConfig pc = new PackageConfig();
    //You only need to change the entity class name, package name and database configuration
    pc.setModuleName("blog"); 
    pc.setParent("com.kuang");
    pc.setEntity("entity"); 
    pc.setMapper("mapper");
    pc.setService("service"); 
    pc.setController("controller");
    mpg.setPackageInfo(pc);
    
    //4. Policy configuration
    StrategyConfig strategy = new StrategyConfig();
    strategy.setInclude("blog_tags","course","links","sys_settings","user_record"," user_say");
    
    // Set the table name to map
    strategy.setNaming(NamingStrategy.underline_to_camel);
    strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    strategy.setEntityLombokModel(true);//Automatic lombok
    
    strategy.setLogicDeleteFieldName("deleted"); 
    
    // Auto fill configuration
    TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
    TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
    ArrayList<TableFill> tableFills = new ArrayList<>();
    tableFills.add(gmtCreate); tableFills.add(gmtModified);
    strategy.setTableFillList(tableFills);
    
    // Optimistic lock
    strategy.setVersionFieldName("version");
    strategy.setRestControllerStyle(true);
    strategy.setControllerMappingHyphenStyle(true);
    
    // localhost:8080/hello_id_2 
    mpg.setStrategy(strategy);
    mpg.execute(); //implement 
	}
}

Topics: Java Maven Mybatis intellij-idea