Mybatis plus is easy to use

Posted by direction on Thu, 17 Feb 2022 22:35:18 +0100

Mybatis-Plus

1 Introduction to mybatis plus

Official website address

Mybatis plus (mp for short) is an enhancement tool of mybatis. Based on mybatis, it is only enhanced without change. It is developed for simplification and 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. 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

2 quick start

  • Create a Spring Boot project

  • pom.xml import dependency
<!-- Database driven -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus -->
<!-- mybatis-plus Developed by ourselves, not official! -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
  • application. Add database configuration to YML (you can also use properties configuration)
================================application.yml=============================================
# DataSource Config
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 152tml

# Configuration log
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
=========================application.properties============================================
# mysql 5 drives different com mysql. jdbc. Driver
# mysql 8 drives different com mysql. cj. jdbc. Driver. The configuration of time zone needs to be added
serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test?
useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

  • entity
// When the class name is inconsistent with the database name, @ TableName is used for mapping
@TableName(value = "mp_user")
public class User {
    /*Specify primary key method:
    * value: The name of the primary key. If it is an id, it can be left blank
    * type: Specify the primary key type and how to generate the primary key value. Type = idtype Auto means automatic growth
    * */
    @TableId(
            value = "id",
            type = IdType.AUTO
    )
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    
    constructor ||setter,getter||toString
}
  • mapper
    // The base Mapper class inherits from the base Mapper class above
@Repository // Represents the persistence layer
public interface UserMapper extends BaseMapper<User> {
    // All CRUD operations have been written
    // You don't need a lot of files like the previous configuration!
}

  • Add @ MapperScan scan Mapper folder

  • Test in test class
@SpringBootTest
public class UserTest {
    // It inherits BaseMapper, and all methods use their own parent class
    // We can also write our own extension methods!
    @Autowired
    private UserMapper userMapper;

    @Test
    public void contextLoads() {
    // The parameter is a Wrapper and condition constructor. We don't need null here
    // Query all users
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

Test results:
User{id=1, name='Jone', age=18, email='test1@baomidou.com'}
User{id=2, name='Jack', age=20, email='test2@baomidou.com'}
User{id=3, name='Tom', age=28, email='test3@baomidou.com'}
User{id=4, name='Sandy', age=21, email='test4@baomidou.com'}
User{id=5, name='Billie', age=24, email='test5@baomidou.com'}

3 insert

3.1 insert demo

    @Test
    // Insert with test id as primary key
    public void test1() {
        User user = new User();
        user.setName("toms");
        user.setAge(20);
        user.setEmail("1234@cc.com");
        int rows = userMapper.insert(user);
        System.out.println("Number of affected rows:" + rows);
        System.out.println("Updated data:" + user);
    }
  • When id is specified as the main key and auto increment is turned on

  • When auto increment is not on

If it is not MySQL 8, the default value of the id inserted into the database needs to be specified by yourself.

3.2 primary key generation strategy

Default id_ The globally unique id of worker adopts the 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!

Set the primary key generation policy: @ TableId(type = IdType.AUTO)

public enum IdType {
    AUTO(0), // Self incrementing database id (database field must be self incrementing!)
    NONE(1), // No primary key set
    INPUT(2), // Manual input
    ID_WORKER(3), // Default globally unique id
    UUID(4), // Globally unique id uuid
    ID_WORKER_STR(5); //ID_WORKER string representation
}

4 update

4.1 update demo

    @Test
    // Test package type update
    public void testUpdate() {
        User user = new User();
        // Automatic splicing of dynamic sql through conditions
        user.setId(16);
        user.setName("Fei Zhang");
        // Note: updateById, but the parameter is an object!
        int rows = userMapper.updateById(user);
        System.out.println("Number of affected rows:" + rows);
    }
  • When the data type of age field is wrapper class

  • When the data type of age field is basic type

To sum up: the data type is the preferred packaging type, and the basic type will have a default value. If it is not modified, it will be updated with the default value.

4.2 automatic update of current time

Alibaba Development Manual: all database tables: gmt_create (creation time), gmt_modified (modified time) almost all tables should be configured!

  • Method 1: database level

1. Add a new field create in the table_ time, update_ time

2. Synchronize entity classes, insert and modify them, and check whether the time is automatic

  • Mode 2: code level

1. Delete the default value and update the database!

2. Annotation needs to be added on the field attribute of entity class

// Add padding to field
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

3. Write a processor to process this annotation!

@Slf4j
@Component // Don't forget to add the processor to the IOC container!
public class MyMetaObjectHandler implements MetaObjectHandler {
    // Population policy at insertion
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill.....");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject
        metaObject
            this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    // Population policy when updating
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill.....");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

5 delete

5.1 delete test

// Test delete
@Test
public void testDeleteById(){
    userMapper.deleteById(1240620674645544965L);
}
// Batch delete by id
@Test
public void testDeleteBatchId(){
    userMapper.deleteBatchIds(Arrays.asList(1240620674645544961L,124062067464554496
                                            2L));
}
// Delete by map
@Test
public void testDeleteMap(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","Madness theory Java");
    userMapper.deleteByMap(map);
}

5.2 logical deletion

Physical delete: remove directly from the database
Logical deletion: it is not removed from the database, but invalidated by a variable! deleted = 1 => deleted = 0

Administrators can view deleted records! Prevent data loss, similar to recycle bin!

1. Add a deleted field in the data table

2. Add attribute in entity class

@TableLogic //Logical deletion
private Integer deleted;

3. Configuration!

// Delete components logically!
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

# Configure logical deletion
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

6 select

6.1 select test

// Test query
@Test
public void testSelectById(){
    User user = userMapper.selectById(1L);
    System.out.println(user);
}
// Test batch query!
@Test
public void testSelectByBatchId(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}
// Using map operations by one of the conditional queries
@Test
public void testSelectByBatchIds(){
    HashMap<String, Object> map = new HashMap<>();
    // Custom query
    map.put("name","Madness theory Java");
    map.put("age",3);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

6.2 paging query

1. Just configure the interceptor component!

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

2. You can use the Page object directly!

// Test paging query
@Test
public void testPage(){
    // Parameter 1: current page
    // Parameter 2: page size
    // After using the paging plug-in, all paging operations become simple!
    Page<User> page = new Page<>(2,5);
    userMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

7 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

  • When updating, bring this version

  • When updating, set version = newVersion where version = oldVersion

  • If the version is incorrect, the update fails

Optimistic lock: 1. Query first to obtain the version number version = 1
-- A
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
-- B The thread finishes first. At this time version = 2,Will lead to A Modification failed!
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1

Test the optimistic lock plug-in of MP:

1. Add version field to the database!

2. We add the corresponding fields to the entity class

@Version //Optimistic lock Version annotation
private Integer version;

3. Register components

// Scan our mapper folder
@MapperScan("com.kuang.mapper")
@EnableTransactionManagement
@Configuration // Configuration class
public class MyBatisPlusConfig {
    // Register optimistic lock plug-in
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

4. Test it!

// Test optimistic lock successful!
@Test
public void testOptimisticLocker(){
    // 1. Query user information
    User user = userMapper.selectById(1L);
    // 2. Modify user information
    user.setName("kuangshen");
    user.setEmail("24736743@qq.com");
    // 3. Perform update operation
    userMapper.updateById(user);
}
// Failed to test optimistic lock! Multithreading
@Test
public void testOptimisticLocker2(){
    // Thread 1
    User user = userMapper.selectById(1L);
    user.setName("kuangshen111");
    user.setEmail("24736743@qq.com");
    // Simulate another thread to perform queue jumping
    User user2 = userMapper.selectById(1L);
    user2.setName("kuangshen222");
    user2.setEmail("24736743@qq.com");
    userMapper.updateById(user2);
    // Spin lock to multiple attempts to submit!
    userMapper.updateById(user); // If there is no optimistic lock, the value of queue jumping thread will be overwritten!
}

8 conditional constructor Wrapper

See the official website for more details

9 automatic code generator

AutoGenerator is the code generator of mybatis plus. Through AutoGenerator, you can quickly generate the code of Entity, Mapper, Mapper XML, Service, Controller and other modules, which greatly improves the development efficiency.

code:

public class AutoMapper {

    public static void main(String[] args) {
        //Create autogenerator, objects in MP
        AutoGenerator ag = new AutoGenerator();

        //Set global configuration
        GlobalConfig gc = new GlobalConfig();
        //Set the generation location of the code and the directory of the disk
        String path = System.getProperty("user.dir");
        gc.setOutputDir(path + "/src/main/java");
        //Set the name of the generated class (naming convention)
        gc.setMapperName("%sMapper");//All Dao classes end with Mapper, such as DeptMapper
        //Set the name of the Service interface
        gc.setServiceName("%sService");//DeptService
        //Set the name of the Service implementation class
        gc.setServiceImplName("%sServiceImpl");//DeptServiceImpl
        //Set the naming of the Controller class
        gc.setControllerName("%sController");//DeptController
        //Set author
        gc.setAuthor("Toro");
        //Set the configuration of the primary key id
        gc.setIdType(IdType.ID_WORKER);
        ag.setGlobalConfig(gc);

        //Set data sourcedatasource
        DataSourceConfig ds = new DataSourceConfig();
        //drive
        ds.setDriverName("com.mysql.jdbc.Driver");
        //Set url
        ds.setUrl("jdbc:mysql://localhost:3306/test");
        //Set the user name of the database
        ds.setUsername("root");
        //Set password
        ds.setPassword("12345");
        //Assign DataSourceConfig to AutoGenerator
        ag.setDataSource(ds);

        //Set Package information
        PackageConfig pc = new PackageConfig();
        //Set the module name, which is equivalent to the package name. Under this package are mapper, service and controller.
        pc.setModuleName("mall");
        //Set the parent package name, and the order is generated under the parent package
        pc.setParent("priv.zwh"); //com.wkcto.order
        ag.setPackageInfo(pc);

        //Set policy
        StrategyConfig sc = new StrategyConfig();
        sc.setNaming(NamingStrategy.underline_to_camel);
        //Set the naming rules that support humps
        sc.setColumnNaming(NamingStrategy.underline_to_camel);
        ag.setStrategy(sc);

        //Execute code generation
        ag.execute();
    }
}

Topics: Mybatis SSM