Development efficiency artifact, mybatis plus

Posted by dineshsjce on Sat, 25 Dec 2021 23:47:19 +0100

Daily Maxim

I am confident, so I succeed.

mybatis plus

Required Foundation:

ssm

javaweb

mysql

javaSE

Knowledge points that must be learned

Why learn from him? Is mybatis not enough?

mybatis is very convenient, and plus will certainly be more convenient

brief introduction

Mybatis simplifies jdbc, and mybatis plus simplifies mybatis


vision

Our vision is to be the best partner of MyBatis, just like Contra 1P and 2P in, and the efficiency is doubled.

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 a more powerful condition constructor to meet various use needs. The basic addition, deletion, modification and query operations do not need to be written by yourself
  • 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 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 get start

Document address: https://mp.baomidou.com/guide/quick-start.html

Using third-party components:

  1. Import corresponding dependencies
  2. Study how dependencies are configured
  3. How to write the code
  4. Improve and expand technical ability

step

  1. Create database Mybatis_plus

  2. Create user table

    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)
    );
    --It's really under development, version(Le Guansuo), deleted((logical deletion) gmt_create,gmt_modified
    
  3. Write the project and initialize the project with springboot

  4. Import related dependencies

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </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>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.0.5</version>
            </dependency>
    

    Introduce dependency description: mybatis plus can save us a lot of code. Try not to use mybatis plus and mybatis at the same time, which will cause version problems

  5. Configure database connection

    #mysql 5 driver: com.mysql.jdbc.Driver
    
    #mysql 8 driver: com.mysql.cj.jdbc.Driver
    # 8. Time zone needs to be configured: serverTimezone=UTC
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    spring.datasource.password=root
    spring.datasource.username=root
    
  6. Different ways

    1. In the past, our traditional method was POJO Dao (connect to mybatis and configure the mapper.xml file) - service controller
    2. After using mybatis plus
      • pojo
      • mapper interface
      • use
  7. Simple and practical

    You only need to implement the corresponding interface on the corresponding mapper. If you want to operate, you can pass in user in the generic type. Then, the corresponding curd will be generated

    //You only need to implement the corresponding interface on the corresponding mapper
    @Repository//Represents the persistence layer
    public interface userMapper extends BaseMapper<user> {
    //    At this point, all crud is written
        //There is no need to configure as much as before
    }
    

    There is a simple crud template in the parent class. After we add generics, the code has been written for us

    test

    Let's query all users of a user

      @Autowired
        private userMapper usermapper;
        @Test
        void contextLoads() {
            List<user> userList = usermapper.selectList(null);
            userList.forEach(System.out::println);
    
        }
    

    Perfect, this is mybatis_ The charm of plus

  1. Think, who will help us accomplish these things? We don't have a sql to write, but we can easily find out all the data

    1. Mybatis plus is all written
    2. The method has been brought and mybatisplus has been written

journal

All our sql is invisible. We want to know how it is executed, which is very important

Add the default log in the configuration file to check the effect first. If there is a need, import the relevant dependencies

#Log configuration
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

result:

After the configuration is completed, we can view the logs. In future learning, we should also observe the automatically generated logs. Slowly, you will find that mybatis plus is a very useful tool,

CRUD expansion

Insert operation

There is a magic thing when testing insertion. It will automatically generate id for us,

Test method:

  user user = new user();
        user.setAge(3);
        user.setName("hyc");
        user.setEmail("3132774018@qq.com");
        int result = usermapper.insert(user);
        System.out.println(result);
        System.out.println(user);

We don't have a setid, but the id is automatically generated. Think about it

![image-20210723150421869]

We all know. Database insert id: globally unique id

At this time, we need to understand,

Primary key generation strategy

Our entity class, in

id ----- "corresponds to our primary key

We need to know one thing at this time: snowflake algorithm

What have we used in our previous study? uuid to generate a globally unique id

Next, learn from the content of the blog

Unique id generation scheme of distributed system: https://www.cnblogs.com/haoxinyue/p/5208136.html

Default unique id: the default is ID_worker (globally unique) is out of date in the new version

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. For the specific implementation code, see https://github.com/twitter/snowflake . The TPS supported by snowflake algorithm can reach about 4.19 million (2 ^ 22 * 1000).

Snowflake algorithm has single machine version and distributed version in engineering implementation. The stand-alone version is as follows. For the distributed version, please refer to meituan leaf algorithm: https://github.com/Meituan-Dianping/Leaf

Next, there are several primary key policies

Source code explanation:

AUTO(0), auto increment
NONE(1), none
INPUT(2), manual input
ID_WORKER(3), globally unique
UUID(4), global one
ID_WORKER_STR(5); Intercepted string representation, ID_ String representation of worker

AUTO(0), auto increment

The first is self increasing:

  1. Add @ TableId(type = IdType.AUTO) to the primary key
  2. First, the primary key of the database must be self incremented, otherwise an error will be reported
  3. After setting, we can test the insertion again and get the results

update operation

Test update operation

Test:

        user user = new user();
        user.setAge(3);
        user.setName("Make sure I'm on my way");
        user.setEmail("3132774018@qq.com");
        int result = usermapper.updateById(user);
        System.out.println(result);
        System.out.println(user);

I tested it twice

There are details, that is, with different requirements, mybatisplus does dynamic sql processing, and all automatically generated sql is dynamically configured

Auto fill

The creation time and modification time are generally completed automatically. We recommend manual updating

Alibaba's Development Manual: gmt_create, creation time, gmt_modified, modification time, almost all tables, configuration, and need to be automated

Method 1: database level (you are not allowed to modify data during work)

  1. Add a new field GMT in the table_ create,

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

        private Date createTime;
        private Date updateTime;
    
  2. Update view results again

Method 2: code level

  1. Delete data defaults and update operations

  2. Update with mybatis plus annotations when needed

    @TableField(fill = FieldFill.INSERT)
        private Date createTime;
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updateTime;
    
  3. Write a processor and implement an interface MetaObjectHandler

    @Slf4j
    @Component  //Don't forget to put our processor in the ioc container
    public class mymetaobjecthandler implements MetaObjectHandler {
        Date date = new Date();
        @Override
        public void insertFill(MetaObject metaObject) {
                log.info("meta insert fill ...");
                //setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
            this.setFieldValByName("createTime",date,metaObject);
            this.setFieldValByName("updateTime",date,metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime",date,metaObject);
        }
    }
    
    
  4. Test inserts and updates

  5. success

Optimistic lock

During the interview, we are often asked about optimistic lock and pessimistic lock. The beginning is very simple

Optimistic lock: as the name suggests, optimistic lock. He always thinks that there will be no problem. No matter what he does, he will not lock it. If there is a problem, he will update the test value again

Pessimistic lock: as the name suggests, he always thinks there will be problems. When to lock it first and then operate it

We mainly understand the optimistic locking mechanism

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
Optimistic lock: 1.Query the version number first version = version+1
-- A
 update user set name = hyc, version = version+1\
   where id = 2 and vsersion=1
-- B If b The thread finishes first. At this time vsersion =2 Will cause A Modification failed
  update user set name = hyc, version = version+1
   where id = 2 and vsersion=1

Test MP's optimistic lock plug-in

  1. Database add field, version

  1. Update entity class

        @Version
        private int version;
    
  2. Register the component and write the version configuration class

        //Register optimistic lock plug-in
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    
    
  3. test

    //If the lock is successful, it will succeed in a single thread
        @Test
        void contextLoads2() {
            user user = new user();
            user.setId(1419289393067204614l);
            user.setAge(3);
            user.setName("Make sure I'm on my way");
            user.setEmail("3132774018@qq.com");
            int result = usermapper.updateById(user);
            System.out.println(result);
            System.out.println(user);
        }
        //  Simulate multithreading, test optimistic lock and preemption
        @Test
        void contextLoads3() {
            user userSel = usermapper.selectById(1l);
            userSel.setId(1l);
            userSel.setAge(3);
            userSel.setName("Make sure I have a smooth journey 000");
            userSel.setEmail("3132774018@qq.com");
            user userSel1 = usermapper.selectById(1l);
            userSel1.setId(1l);
            userSel1.setAge(3);
            userSel1.setName("Make sure I have a smooth journey 111");
            userSel1.setEmail("3132774018@qq.com");
            int result1 = usermapper.updateById(userSel1);
            int result = usermapper.updateById(userSel);
    
        }
    }
    
    

    Optimistic lock thread queue jumping results

Query operation

Code example

Single query

user userSel = usermapper.selectById(1l);
System.out.println(userSel);

Batch query

List<user> userList = usermapper.selectBatchIds(Arrays.asList(1, 2, 3));
userList.forEach(System.out::println);

Condition query

HashMap<String,Object> map = new HashMap<>();
map.put("name","Make sure I'm on my way");
List<user> users = usermapper.selectByMap(map);
users.forEach(System.out::println);

Paging query

Pagination is used as much as ten times on the website

  1. Original limit page
  2. pageHelper third party
  3. MP actually has a built-in paging plug-in

How to use it?

1. MP paging plug-in component import

   @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // After setting the requested page to be larger than the maximum page, true will be called back to the home page, false will continue to request, and the default is false
        // paginationInterceptor.setOverflow(false);
        // Set the maximum number of single page restrictions, 500 by default, - 1 unlimited
        // paginationInterceptor.setLimit(500);
        // Turn on the join optimization of count, only for some left join s
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }

2. Directly use the Page object!

//Test paging query
    @Test
    void selectByPage(){
        //Parameter 1: current page, parameter 2: number and size of pages
        Page<user> page = new Page<>(1,5);
        usermapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }

Delete operation

Code example:

    //delete
    @Test
void deleteByid(){
        usermapper.deleteById(1l);
}
//Batch delete by id
@Test
void deleteBybatchid(){
        usermapper.deleteBatchIds(Arrays.asList(1419289393067204612l,1419289393067204613l));
}
//Delete according to map conditions
@Test
void deleteBymapid(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("id","1419289393067204614");
    usermapper.deleteByMap(map);
}

Some problems will be encountered in work, such as logical deletion

Logical deletion

Physical delete: remove directly from the database

Logical deletion: there is no overflow in the database, but a variable to invalidate it!

Common functions: administrators can view deleted records to prevent data loss, similar to recycle bin

Test:

  1. Add a deleted field to the data table,

  1. When updating the entity class, we add @ TABLELOGIC on the orm object that needs to represent logical deletion to represent logical deletion

    @TableLogic
      private  int deleted;
    
  2. Delete component configuration logically

     @Bean
    public ISqlInjector sqlInjector(){
         return new LogicSqlInjector();
    }
    
  3. In the configuration file, the corresponding database field is deleted, 0,1

    #Logical deletion
    mybatis-plus.global-config.db-config.logic-delete-value=1
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
    
  4. In the test, we delete, but update the statement and change the logically deleted fields,

When we check the database again, the records are still there, but the fields have been updated; Logically deleted fields

When we search again, if the deleted value is 1, it will be automatically spliced into the subsequent sql to add the field that only queries the deleted value of 0

  1. We must master all the above crud and its extension operations, which will greatly improve the efficiency

Performance analysis plug-in (abandoned in the new version) the new version has a new analysis instead

In our usual development, we will encounter some slow sql. Test, druid

MP also provides a performance analysis plug-in, which stops running if it exceeds the time limit

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-9A3cWgSe-1629434124333)(mybatisplus.assets/image-20210726092011898.png)]

After importing, executing sql will have corresponding things

As long as the specified execution time is exceeded, an exception is thrown

Benefits:

Conditional constructor warpper

Very important,: warpper

We can use it instead of writing some complex sql

All our conditions can be used with this constructor

PS: remember to view the output sql for analysis

Test one,

  @Test
    void contextLoads() {
        QueryWrapper<user> wrapper = new QueryWrapper();
        wrapper
                .isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        usermapper.selectList(wrapper).forEach(System.out::println);
    }

Test two

    @Test
    void Test2(){
        //Difference between right and left% t, t%
        QueryWrapper<user> wrapper = new QueryWrapper();
            wrapper
                    .notLike("name","e")
                    .likeRight("email","t");
        List<Map<String, Object>> maps = usermapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

Test the rest yourself

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.

Need to rely on

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>

Remember to import the dependencies required by your template engine. Here we test using the default

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>latest-velocity-version</version>
</dependency>

Test: configured code generator

   //Build a code generator object
        AutoGenerator generator = new AutoGenerator();
        //Configuration policy
        //1. Global configuration
        GlobalConfig gc = new GlobalConfig();
        String projectpath = System.getProperty("user.dir");//Project address
        gc.setOutputDir(projectpath+"/src/main/java");
        gc.setAuthor("hyc");
        gc.setOpen(false);
        gc.setFileOverride(false);//Overwrite
        gc.setServiceImplName("%sService");//Interface prefix, no
        gc.setIdType(IdType.ID_WORKER);//Policy id
        gc.setDateType(DateType.ONLY_DATE);//Time type
        gc.setSwagger2(true);//Turn on Swagger
        generator.setGlobalConfig(gc);

        //2. Data source configuration
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDbType(DbType.MYSQL);//This database
        generator.setDataSource(dsc);
        //3. Package configuration
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.hyc");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("Service");
        pc.setController("controller");
        generator.setPackageInfo(pc);

        //Policy configuration
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");//There are many table names for configuration mapping, such as user, role and region
        strategy.setNaming(NamingStrategy.underline_to_camel);//hump
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//Name conversion of database
        strategy.setEntityLombokModel(true);//Open lombok
        strategy.setRestControllerStyle(true);
        //Logical deletion
        strategy.setLogicDeleteFieldName("deleted");
        //Auto fill
        TableFill gmtcreate =new TableFill("create_time", FieldFill.INSERT);//Fill in when adding
        TableFill gmtupd=new TableFill("update_time", FieldFill.INSERT_UPDATE);//Fill in when adding and updating again
        ArrayList<TableFill> tablefill = new ArrayList<>();
        tablefill.add(gmtcreate);
        tablefill.add(gmtupd);
        strategy.setTableFillList(tablefill);
        //Optimistic lock
        strategy.setVersionFieldName("version");//A series is called a variable
        strategy.setRestControllerStyle(true);//Enable restful style interface
        strategy.setControllerMappingHyphenStyle(true);//Request style, localhost/v1/id_ps_..
        generator.setStrategy(strategy);

        generator.execute();

effect:

end

At the end, the mp is really too fierce and greatly reduced. Some operations and automation have helped you do a lot of things. It is a very reliable tool to improve efficiency!!! Finish

Topics: Java Mybatis IDEA