Learning notes - mybatis plus

summary

Official website: MyBatis-Plus (baomidou.com)

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. There is also a powerful condition constructor to meet various use needs
  • Support Lambda form call: through Lambda expression, it is convenient to write various query conditions without worrying 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 problem of primary key
  • 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

Quick start

Create a new springboot web project

Import dependency: try not to import mybatis and mybatis plus at the same time

<!--Database driven-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!--mybatis-plus--->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

Configure connection database:

# DataSource Config
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #schema: classpath:db/schema-h2.sql
    #data: classpath:db/data-h2.sql
    url: jdbc:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: yang
    password: 123456

Write entity class:

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

*Write mapper interface~~~~*

@Repository // Represents the persistence layer
//Inherit BaseMapper on the corresponding mapper interface and pass in generics
public interface UserMapper extends BaseMapper<User> {
}

Start mapper scan @ MapperScan

@MapperScan("com.yang.mapper")//Scan mapper folder
@SpringBootApplication
public class SpringbootMybatisplusApplication {

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

Test:

@Autowired
private UserMapper userMapper;

@Test
void contextLoads() {
    List<User> userList = userMapper.selectList(null);
    for (User user : userList) {
        System.out.println(user);
    }
}

Configuration log

Insert test

User user = new User();
user.setAge(3);
user.setEmail("134679262@qq.com");
user.setName("123");
int insert = userMapper.insert(user);
System.out.println(insert);

Insert succeeded, found automatically generated id!! (the table name is required to be consistent with the entity class name)

Primary key generation strategy

Snowflake generation algorithm: (default)

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! I

Other policies: @ TableId

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • AUTO primary key AUTO increment requires the database to set AUTO increment
  • NONE no primary key set
  • INPUT manual INPUT

Update test

@Test
void testUpdate(){
    User user = new User();
    user.setId(3L);
    user.setAge(5);
    int update = userMapper.updateById(user);
    System.out.println(update);
}

sql is dynamically configured according to parameters~~

Auto fill

Database level (not recommended)


)

And synchronize in the entity class

    private Date creat_time;
    private Date update_time;

Code level

Remove default

Set @ TableField on the property of the entity class

@TableField(fill = FieldFill.INSERT) //Fill on insert
private Date creat_time;
@TableField(fill = FieldFill.UPDATE) //Fill on update
private Date update_time;

Custom population policy

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill....");

        this.setFieldValByName("creat_time",new Date(),metaObject);
        this.setFieldValByName("update_time",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill....");
        this.setFieldValByName("update_time",new Date(),metaObject);
    }
}

Optimistic lock

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

Pessimistic lock: hence the name Siyi is very pessimistic. It always thinks that there is always a problem and it will lock no matter what it does! Operate again|

Optimistic lock implementation method:

  • When the record is fetched, the current version is obtained
  • Carry version when updating
  • When performing an update operation, version= new_verison where version = old_version
  • When the version s do not match, the update fails

test

Add version field

Annotation for configuring version attribute @ Version MP

@Version
private Integer version;

Register components:

@Configuration
//@EnableTransactionManagement  ??? Not on the official website
@MapperScan("com.yang.mapper") 
public class MybatisPlusConfig {
    /**
     * new edition
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

Test:

  • success
@Test
    void test1(){
        User user = userMapper.selectById(1487730131458940930L);
        user.setAge(5);
        user.setName("Ah, ah, ah");
        int update = userMapper.updateById(user);
    }

Version will be taken out first and then updated after version+1

  • fail
@Test
void test2(){
    User user = userMapper.selectById(1487730131458940930L);
    user.setAge(5);
    user.setName("Ha ha ha ha");

    //Simulate multithreading being cut in line
    User user2 = userMapper.selectById(1487730131458940930L);
    user2.setAge(5);
    user2.setName("1111");
    int update2 = userMapper.updateById(user2);

    int update = userMapper.updateById(user);

}

When there is no optimistic lock, this data will be overwritten by "hahaha", but under the action of optimistic lock, the subsequent update statement fails

be careful:

  • The only supported data types are: int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • newVersion = oldVersion + 1 under integer type
  • newVersion will be written back to entity
  • Only updateById(id) and update(entity, wrapper) methods are supported
  • Under the update(entity, wrapper) method, the wrapper cannot be reused!!!

query

Multi Id query

@Test
void testquery(){
    List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    for (User user : userList) {
        System.out.println(user);
    }
}

map conditional query cannot realize fuzzy query

 @Test
    void testquery1(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","1111");
        List<User> userList = userMapper.selectByMap(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

Paging query

   // the latest version
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

use:

@Test
void testpage(){
    Page<User> page = new Page<>(1,3); //Page number, page size

     userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);
}

Logical deletion

Physical delete: delete from database

Logical deletion: in the database, a variable is used to invalidate it to prevent data loss

@TableLogic //Logical deletion
private Integer deleted;
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag # Global logically deleted entity field name (since 3.3.0, can be ignored after configuration, step 2 is not configured)
      logic-delete-value: 1 # Logical deleted value (default = 1)
      logic-not-delete-value: 0 # Logical undeleted value (default is 0)

The actual operation is to update. Later, the query criteria of deleted=0 will be spliced automatically during query, and only the columns that have not been deleted logically will be queried

Performance analysis plug-in?????

Do not use in the production environment

This function relies on p6spy components to output and print SQL perfectly and the execution time is long

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>Latest version</version>
</dependency>
  • application.yml modification:
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
  • spy.properties configuration:

    driverlist=com.mysql.cj.jdbc.Driver
    
    logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat
    #logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat
    
    databaseDialectDateFormat=yyyy-MM-dd HH:mm:ss
    
    appender=com.p6spy.engine.spy.appender.StdoutLogger
    
    
#3.2.1 use of the above
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1 the following are used or not configured:
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# Custom log printing
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#Log output to console
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# Use the logging system to record sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# Set p6spy driver agent
deregisterdrivers=true
# Remove JDBC URL prefix
useprefix=true
# Log exceptions for configuration records. The result sets that can be removed include error,info,batch,debug,statement,commit,rollback,result,resultset
excludecategories=info,debug,result,commit,resultset
# Date format
dateformat=yyyy-MM-dd HH:mm:ss
# The actual drive can be multiple
#driverlist=org.h2.Driver
# Enable slow SQL logging
outagedetection=true
# Slow SQL record standard 2 seconds
outagedetectioninterval=2

Conditional constructor

  • isNotNull ge
@Test
void test1(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
        .isNotNull("name")
        .isNotNull("email")
        .ge("age",18); // name and email are not empty and age > = 18
    userMapper.selectList(wrapper).forEach(System.out::println);
}

  • eq
@Test
void test2(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","1111");
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}

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

}

  • notLike likeLeft
 @Test
    void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.notLike("name","J")
                .likeLeft("name","3"); //   %3

        userMapper.selectMaps(wrapper).forEach(System.out::println);
    }

Keywords: mybatis-plus

Added by TronB24 on Tue, 01 Feb 2022 21:17:38 +0200