编程知识 cdmana.com

Mybatis reverse engineering and the use of new version mybatisplus 3.4 reverse engineering

Mybatis and MybatisPlus3.4 Use

1 RESTFUL

Front and back wind in the project you develop , Between the front and back end is the interface for request and response , When the back end provides a request to the front end, it will expose a URL;URL Your design cannot be arbitrary , Need to comply with certain design specifications ----RESTFUL.

RESTful It's a kind of web api Standards for , It's a kind of url Design style / standard

  • Every URL The request path represents the only resource on the server .

    Conventional URL Design :

    http://localhost:8080/goods/delete?goodsId=1 goods 1

    http://localhost:8080/goods/delete?goodsId=2 goods 2

    RESTful Design :

    http://localhost:8080/goods/delete/1 goods 1

    http://localhost:8080/goods/delete/1 goods 1

    Example :

        @DeleteMapping("/delete/{id}")
        public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) {
            return new ResultVO(10003," The request is successful ",goodsId);
        }
    
  • Different requests are used to represent different operations , Ensure that the only URL Corresponding to a unique resource

    • @GetMapping Inquire about
    • @PutMapping modify
    • @PostMapping add to
    • @DeleteMapping Delete

    according to id Delete a product :

     //http://localhost:8080/goods/1	[delete]
    	@DeleteMapping("/{id}")
     public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) {
         return new ResultVO(10003," The request is successful ",goodsId);
     } 
    

    according to id Query a product :

     //http://localhost:8080/goods/1	[get]
    	@GetMapping("/{id}")
     public ResultVO getGoods(@PathVariable("id") Integer goodsId) {
         return new ResultVO(10003," The request is successful ",goodsId);
     }
    
  • The resource representation of the interface response uses JSON

    • You can add... On the control class or the required interface method @ResponseBody The annotation says that the returned object is formatted as JSON
    • You can also use... On control classes @RestController Declare controller
  • front end (Android\ios\PC) Through stateless HTTP The protocol interacts with the back-end interface

2 Reverse engineering

mybatis The official provides a method to generate data from database tables mybatis Tools for executing code , This tool is a reverse engineering

Reverse engineering : For database single table —-> The generated code (mapper.xml、mapper.java、pojo..)

What I started using here is mybatis Reverse engineering , Can generate mapper.xml、mapper.java、pojo

Later I want to try to use MP Do reverse engineering , So two ways are used , In terms of brevity , still MP It's more convenient .

2.1 tkMybatis Reverse engineering

Reverse engineer and automatically add swagger annotation , Note the need for beans Of pom Also add swagger rely on

2.1.1 Import dependence

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.1.5</version>
</dependency>
  • Modify startup class annotation @MapperScan My bag , Because this annotation also has a package that is org.mybatis.spring.annotation.MapperScan;
image-20210925153510152

2.1.2 Add the plug-in

    <build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.22</version>
                    </dependency>
                    <!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client --><!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>4.1.5</version>
                    </dependency>
                    <dependency>
                        <groupId>com.github.misterchangray.mybatis.generator.plugins</groupId>
                        <artifactId>myBatisGeneratorPlugins</artifactId>
                        <version>1.2</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

After the synchronization is successful, a

image-20210925154311915

2.1.3 Add configuration file

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- Import property configuration -->
    <!--    <properties resource="db.properties"></properties>-->
    <!-- Specify... For a specific database jdbc drive jar The location of the package -->
    <!--<classPathEntry location="${jdbc.location}"/>-->
    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!-- Combined with universal Mapper plug-in unit   Specify generation  Mapper  Inheritance template -->
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="com.mymall.general.GeneralDao"/>
        </plugin>
        <!--pojo implements Serializable -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
        <!--pojo Class toString Method -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
        <!-- Overlay generation XML file   Every time you execute , Put the old mapper.xml Overwrite instead of merge -->
<!--                <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />-->

        <!--  Automatically for entity Generate swagger2 file -->
                <plugin type="mybatis.generator.plugins.GeneratorSwagger2Doc">
                    <property name="apiModelAnnotationPackage" value="io.swagger.annotations.ApiModel"/>
                    <property name="apiModelPropertyAnnotationPackage" value="io.swagger.annotations.ApiModelProperty"/>
                </plugin>
        <!-- Be careful , plugin  It needs to be written in commentGenerator above -->

        <commentGenerator>
            <!--  Remove automatically generated comments or not  true: yes  : false: no  -->
            <property name="suppressAllComments" value="false" />
        </commentGenerator>
        <!--jdbc Database connection to  -->
        <jdbcConnection
                driverClass="com.mysql.cj.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&amp;serverTimezone=GMT%2b8"
                userId="root"
                password="123456">
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>

        <!--  Generate  JavaBean  Object rewriting  toString Method  -->
        <!--        <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />-->
        <!--  Generate  JavaBean  Object inheritance  Serializable  class  -->
        <!--        <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />-->
        <!--  Generate  JavaBean  Object rewriting  equals  and  hashCode  Method  -->
        <!-- <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin" /> -->

        <!--  Corresponding generated pojo Location package  -->
        <javaModelGenerator targetPackage="com.mymall.entity" targetProject="src/main/java">
            <!--  Whether the model add to   Constructors  -->
            <property name="constructorBased" value="true"/>
        </javaModelGenerator>

        <!--  Corresponding generated mapper.xml In the directory  -->
        <sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>

        <!--  To configure mapper Corresponding java mapping  -->
        <javaClientGenerator targetPackage="com.mymall.dao" targetProject="src/main/java"
                             type="XMLMAPPER"/>
        <!--     Configuration needs to specify the generated database and tables ,% For all tables , Don't do this in development , Many useless tables may be generated -->
        <!--        <table tableName="%"/>-->
        <table tableName="category" />
        <table tableName="index_img" />
        <table tableName="order_item" />
        <table tableName="orders" />
        <table tableName="product" />
        <table tableName="product_comments" />
        <table tableName="product_img" />
        <table tableName="product_params" />
        <table tableName="product_sku" />
        <table tableName="shopping_cart" />
        <table tableName="user_addr" />
        <table tableName="user_login_history" />
        <table tableName="users" />

        <!--  <table schema="" tableName="oauth_access_token"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
              <domainObjectRenamingRule searchString="^Tb" replaceString="" />
          </table>
          <table schema="" tableName="oauth_approvals"  enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
              <domainObjectRenamingRule searchString="^Tb" replaceString="" />
          </table>-->
        <!-- List all the tables you want to generate  -->
    </context>
</generatorConfiguration>

  • Adjust configuration information

    • establish GeneralDao Interface

      image-20210925155522704
      package com.mymall.general;
      
      import tk.mybatis.mapper.common.Mapper;
      import tk.mybatis.mapper.common.MySqlMapper;
      
      /**
       * @author 18230
       * @version 1.0.0
       * @ClassName GereralDao.java
       * @Description
       * @createTime 2021 year 09 month 25 Japan  15:50:00
       */
      public interface GeneralDao<T> extends Mapper<T>, MySqlMapper<T> {
      }
      
      
      <!-- To configure GeneralDao-->
      <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
          <property name="mappers" value="com.mymall.general.GneralDao"/>
      </plugin>
      
    • Configure the database connection information

      <!--jdbc Database connection to ,url Do not modify the following configuration  -->
      <jdbcConnection
              driverClass="com.mysql.cj.jdbc.Driver"
              connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&amp;serverTimezone=GMT%2b8"
              userId="root"
              password="123456">
      </jdbcConnection>
      
    • Configure the entity classpath

      <!--  Corresponding generated pojo Location package  -->
      <javaModelGenerator targetPackage="com.mymall.entity" targetProject="src/main/java">
          <!--  Whether the model add to   Constructors  -->
          <property name="constructorBased" value="true"/>
      </javaModelGenerator>
      
    • To configure mapper.xml Catalog

      <!--  Corresponding generated mapper.xml In the directory  -->
      <sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>
      
    • To configure dao The directory of and the name of the generated table

       <!--  To configure mapper Corresponding java mapping  -->
      <javaClientGenerator targetPackage="com.mymall.dao" targetProject="src/main/java"
                           type="XMLMAPPER"/>
      <!--     Configuration needs to specify the generated database and tables ,% For all tables , Don't do this in development , Many useless tables may be generated -->
      <!--        <table tableName="%"/>-->
      <table tableName="category" />
      <table tableName="index_img" />
      <table tableName="order_item" />
      <table tableName="orders" />
      <table tableName="product" />
      <table tableName="product_comments" />
      <table tableName="product_img" />
      <table tableName="product_params" />
      <table tableName="product_sku" />
      <table tableName="shopping_cart" />
      <table tableName="user_addr" />
      <table tableName="user_login_history" />
      <table tableName="users" />
      
    • Set profile generatorConfig.xml Configuration to reverse engineering maven Plug in

      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-maven-plugin</artifactId>
      <version>1.3.5</version>
      <configuration>
          <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
      </configuration>
      

2.1.4 Reverse execution

image-20210925161111865

2.1.5 Generate successfully

image-20210925163516160
  • The generated entity Cut to beans In subprojects

    The generated entity Move to beans An error will appear after the directory , Because of the use of tkMapper Annotations , So we need to tkMapper The dependency of is cut directly to beans in ,mapper Project references beans So we can no longer pom In a statement tkMapper Rely on the .

2.1.6 Use tkMybatis

package com.qc.dao;

import com.qc.TkMapperDemoApplication;
import com.qc.entity.Category;
import org.apache.ibatis.session.RowBounds;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author 18230
 * @version 1.0.0
 * @ClassName CategoryDaoTest.java
 * @Description
 * @createTime 2021 year 09 month 05 Japan  20:40:00
 */
@SpringBootTest(classes = TkMapperDemoApplication.class)
@RunWith(SpringRunner.class)
public class CategoryDaoTest {
    @Autowired
    private CategoryDao categoryDao;

    @Test
    public void testInsert() {
        Category category = new Category(0,"test02",1,0,"01.png","hehe","111.jpg","black");
        // Insert data into the table , Return results ,1, success 
        //int i = categoryDao.insert(category);
        // After the data is inserted, the generated primary key is returned to the object for saving 
        int i = categoryDao.insertUseGeneratedKeys(category);
        System.out.println(category.getCategoryId());
        assertEquals(1,i);
    }

    @Test
    public void testUpdate() {
        Category category = new Category(13,"test03",1,0,"01.png","hehe","111.jpg","black");
        // Modify the data according to the primary key 
        int i = categoryDao.updateByPrimaryKey(category);
        assertEquals(1,i);
    }

    @Test
    public void testDelete() {
        // Delete data according to the primary key 
        int i = categoryDao.deleteByPrimaryKey(13);
        assertEquals(1,i);

    }

    @Test
    public void testSelect1() {
        // Query all 
        List<Category> categories = categoryDao.selectAll();
        for (Category category : categories) {
            System.out.println(category);
        }
    }

    @Test
    public void testSelect2() {
    //     Query according to the primary key 
        Category category = categoryDao.selectByPrimaryKey(13);
        System.out.println(category);
    }

    @Test
    public void testSelect3() {
    //     Conditions of the query 
    //    1. Create a example encapsulation , Category category Query criteria 
        Example example = new Example(Category.class);
        Example.Criteria criteria = example.createCriteria();
        //criteria.andEqualTo("categoryLevel", 1);
        criteria.andLike("categoryName", "% dry %");
        List<Category> categories = categoryDao.selectByExample(example);
        for (Category category : categories) {
            System.out.println(category);
        }
    }

    @Test
    public void testSelect4() {
    //     Paging query 
        int pageNum = 2;
        int pageSize= 5;
        int start =(pageNum-1)*pageSize;
        RowBounds rowBounds = new RowBounds(start,pageSize);
        List<Category> categories = categoryDao.selectByRowBounds(new Category(), rowBounds);
        for (Category category : categories) {
            System.out.println(category);
        }
    //     Total number of records queried 
        int i = categoryDao.selectCount(new Category());
        System.out.println(i);
    }

    @Test
    public void testSelect5() {
        // Preparation conditions 
        Example example = new Example(Category.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("categoryLevel", 1);
        // Prepare paging conditions 
        int pageNum = 1;
        int pageSize= 3;
        int start =(pageNum-1)*pageSize;
        RowBounds rowBounds = new RowBounds(start,pageSize);
        // Conditional pagination display 
        List<Category> categories = categoryDao.selectByExampleAndRowBounds(example, rowBounds);
        for (Category category : categories) {
            System.out.println(category);
        }
    //     Query the number of records that meet the criteria 
        int i = categoryDao.selectCountByExample(example);
        System.out.println(i);
    }
}

2.2 MybatisPlus Use the tutorial

2.2.1 stay mapper Add dependencies to subprojects

Creating mapper Sub projects have been added mybatis-plus-boot-starter, So there is no need to add additional dependencies

2.2.2 To configure application.yml

Then used mysql8 when , need mysql The drive is the same as :com.mysql.cj.jdbc.Driver, At the same time, you need to add time zone settings :serverTimezone=GMT%2b8

datasource:
    druid:
      # Database connection driver 
      driver-class-name: com.mysql.cj.jdbc.Driver
      # Database connection address 
      url: jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true
      # Database connection user name and password 
      username: root
      password: 123456

2.2.3 To configure @MapperScan

package com.mymall;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.oas.annotations.EnableOpenApi;

@SpringBootApplication
@MapperScan("com.mymall.dao")
@EnableOpenApi
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

2.2.4 Write entity class Users

package com.mymall.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
    Integer userId;
    String username;
    String password;
}

2.2.5 To write Mapper.java Inheritance template BaseMapper

package com.mymall.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mymall.entity.Users;
import org.springframework.stereotype.Repository;

@Repository
public interface UsersMapper extends BaseMapper<Users> {
}

2.2.6 Test whether... Can be called normally MP

package com.mymall;

import com.mymall.entity.Users;
import com.mymall.dao.UsersMapper;
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 ApiApplicationTests {
    @Autowired
    private UsersMapper usersMapper;

    @Test
    void contextLoads() {
        List<Users> users = usersMapper.selectList(null);
        for (Users user : users) {
            System.out.println(user);
        }
        System.out.println(users);
    }

}

Test success !

2.2.7 Configuration log

mybatis-plus:
  configuration:
#     Configuration log 
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

According to the effect

image-20211001090948807

2.2.8 CRUD Expand

2.2.8.1 Database insert id The default value of : The only one in the world id
  • Generation strategy : Distributed systems are unique ID Generate scheme summary - nick hao - Blog Garden (cnblogs.com)

  • Snowflake algorithm :snowflake yes Twitter Open source distributed ID generating algorithm , The result is a long Type ID. The central idea is this : Use 41bit As milliseconds ,10bit As a machine ID(5 individual bit It's the data center ,5 individual bit Machine ID),12bit As a serial number in milliseconds ( It means that every node can produce 4096 individual ID), And finally, there's a sign bit , Forever 0. The specific implementation code can be seen in https://github.com/twitter/snowflake. Snowflake algorithm supports TPS You can achieve 419 All around (2^22*1000).

  • Be careful : Use snowflakes or uuid The fields in the data cannot be self incremented , Otherwise it won't work .

  • Set requirements :

    • The primary key needs to be set to auto increment

    • Add... To the entity class field MP annotation @TableId(type = IdType.ASSIGN_ID)

    • IdType Type source code

      package com.baomidou.mybatisplus.annotation;
      
      import lombok.Getter;
      
      /**
       *  Generate ID Type enumeration class 
       *
       * @author hubin
       * @since 2015-11-10
       */
      @Getter
      public enum IdType {
          /**
           *  database ID Self increasing 
           * <p> Please make sure that the database is set with  ID Self increasing   Otherwise it will not work </p>
           */
          AUTO(0),
          /**
           *  The type is not set as primary key type ( The annotation follows the whole situation , Global Rio equals  INPUT)
           */
          NONE(1),
          /**
           *  User input ID
           * <p> This type can be filled by registering the auto fill plug-in </p>
           */
          INPUT(2),
      
          /*  following 2 Types 、 Only when inserting objects ID  It's empty , To automatically fill in . */
          /**
           *  Distribute ID ( The primary key type is number or string),
           *  Default implementation class  {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}( Snowflake algorithm )
           *
           * @since 3.3.0
           */
          ASSIGN_ID(3),
          /**
           *  Distribute UUID ( The primary key type is  string)
           *  Default implementation class  {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
           */
          ASSIGN_UUID(4),
      
          private final int key;
      
          IdType(int key) {
              this.key = key;
          }
      }
      
  • Insert Automatic generation id

    @Test// Test insert 
    public void insertTest(){
        User user = new User();
        user.setName("wsk");
        user.setEmail("2803708553@qq.com");
        Integer result = userMapper.insert(user); // It will help us automatically generate id
        System.out.println(result); // Rows affected 
        System.out.println(user); // Log discovery id It will automatically backfill 
    }
    
image-20211001103514119
2.2.8.2 Auto fill

Creation time 、 Change the time ! These operations are generally automated , We don't want to manually update

Alibaba Development Manual ︰ Almost all tables need to be configured gmt_create、gmt_modified ! And it needs to be automated

  • Mode one : Database level ( It is not allowed to modify the database level in the work )

    1、 Add fields... To the table :create_time,update_time

    -- auto-generated definition
    create table mp_user
    (
        user_id     bigint auto_increment comment ' user id'  primary key,
        username    varchar(32)                        not null comment ' user name ',
        password    varchar(32)                        not null comment ' password ',
        create_time datetime default CURRENT_TIMESTAMP not null comment ' Creation time ',
        update_time datetime default CURRENT_TIMESTAMP not null comment ' Update time '
    );
    

    2、 Update the member variables in the entity class

    package com.mymall.entity;
    
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.Date;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class MpUser {
        @TableId(type = IdType.ASSIGN_ID)
        Long userId;
        String username;
        String password;
        Date createTime;
        Date updateTime;
    }
    
    

    3、 The code that inserts or updates a piece of data before running again shows the successful automatic insertion time

    image-20211001112149597

  • Mode two : Code level

    1、 Delete the default value of the database , update operation !

    2、 You need to add annotation to the field attribute of entity class

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class MpUser {
        @TableId(type = IdType.ASSIGN_ID)
        Long userId;
        String username;
        String password;
        // Comments on insertion 
        @TableField(fill = FieldFill.INSERT)
        Date createTime;
        // Comments when updating 
        @TableField(fill = FieldFill.UPDATE)
        Date updateTime;
    }
    

    Annotation details

    package com.baomidou.mybatisplus.annotation;
    /**
     *  Field fill policy enumeration class 
     * <p>
     *  Judge the injected  insert  and  update  Of  sql  Whether the script ignores the field in the corresponding case  if  Tag generation 
     * <if test="...">......</if>
     *  Judge priority ratio  {@link FieldStrategy}  high 
     * </p>
     * @author hubin
     * @since 2017-06-27
     */
    public enum FieldFill {
        /**
         *  Default not to handle 
         */
        DEFAULT,
        /**
         *  Fill in fields when inserting 
         */
        INSERT,
        /**
         *  Fill in fields when updating 
         */
        UPDATE,
        /**
         *  Fill in fields when inserting and updating 
         */
        INSERT_UPDATE
    }
    
    

    3、 Write a processor to handle the annotation !

    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); //  Starting version  3.3.0( Recommended )
            //  perhaps 
            this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); //  Starting version  3.3.3( recommend )
            //  perhaps 
            this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); //  You can also use (3.3.0  This method has bug)
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); //  Starting version  3.3.0( recommend )
            //  perhaps 
            this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); //  Starting version  3.3.3( recommend )
            //  perhaps 
            this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); //  You can also use (3.3.0  This method has bug)
        }
    }
    

    matters needing attention :

    • The filling principle is to give directly to entity Property setting value of !!!
    • Annotation specifies that the attribute must have a value in the corresponding case , If there is no value, the entry will be null
    • MetaObjectHandler The policies of the default methods provided are : If the property has a value, it does not override , If the filling value is null It doesn't fill in
    • Fields must declare TableField annotation , attribute fill Choose the corresponding strategy , The statement informed Mybatis-Plus Need to reserve Injection SQL Field
    • Fill the processor MyMetaObjectHandler stay Spring Boot You need to state @Component or @Bean Inject
    • According to the notes FieldFill.xxx and Field name as well as Field type To distinguish between... That must use a parent class strictInsertFill perhaps strictUpdateFill Method
    • You don't need to distinguish by anything that can use a parent class fillStrategy Method

    4. Test run insert or update statements

2.2.9 Optimism lock

During the interview, I am often asked about optimism / Pessimistic locking , This is very simple

Optimism lock : As the name suggests, very optimistic , He always thought there would be no problem , No matter what you do, don't lock it ! If something goes wrong , Update the value test again

Pessimistic locking : As the name suggests, very pessimistic , He always thinks there's a problem , Whatever you do, it's locked ! To operate again !

When a record is to be updated , I hope this record hasn't been updated by others

Optimistic lock implementation :

  • When taking out the record , Get current version

  • update , Take this with you version

  • On update ,set version = newVersion where version = oldVersion

  • If version incorrect , Failed to update

     Optimism lock : First query , Get version number 
    -- A
    update user set name = "wsk",version = version+1 
    where id = 1 and version = 1
    -- B  (B The thread finished first , here version=2, It can lead to A Thread modification failed !)
    update user set name = "wsk",version = version+1 
    where id = 1 and version = 1
    
  1. Update the database , add to version Field

    -- auto-generated definition
    create table mp_user
    (
        user_id     bigint auto_increment comment ' user id' primary key,
        username    varchar(32)                        not null comment ' user name ',
        password    varchar(32)                        not null comment ' password ',
        version     int                                null comment ' Optimism lock ',
        create_time datetime default CURRENT_TIMESTAMP not null comment ' Creation time ',
        update_time datetime default CURRENT_TIMESTAMP not null comment ' Update time '
    );
    
  2. Add corresponding fields and annotations to the entity class

     @Version
    Integer version;
    
  3. Certified components

    // scanning mapper Folder 
    @MapperScan("com.mymall.dao")// hand mybatis It's done , You can scan this configuration class 
    @EnableTransactionManagement// Manage transactions automatically 
    @Configuration// Configuration class 
    public class MyBatisPlusConfig {
        // Register optimistic lock plugin 
        @Bean
    	public MybatisPlusInterceptor mybatisPlusInterceptor() {
        	MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        	interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        	return interceptor;
    	}
    }
    
  4. test

    • Test optimistic lock successfully

      @Test
       void testOptimisticLocker1() {
              //1、 Query user information 
              MpUser mpUser = mpUserMapper.selectById(1L);
              //2、 Modify user information 
              mpUser.setUsername("qq");
              //3、 Perform an update operation 
              int update = mpUserMapper.updateById(mpUser);
              System.out.println(mpUser);
          }
      
    • Simulated multithreading test optimistic lock insert data failed

       @Test
      void testOptimisticLocker2() {
          // Threads 1
          MpUser mpUser = mpUserMapper.selectById(1L);
          mpUser.setUsername("aa");
          mpUser.setPassword("666666");
          // Simulate another thread performing queue jumping operation 
          MpUser mpUser1 = mpUserMapper.selectById(1L);
          mpUser1.setUsername("bb");
          mpUser1.setPassword("12344444");
          mpUserMapper.updateById(mpUser1);
          // Spinlock to multiple attempts to commit !
          mpUserMapper.updateById(mpUser);// If there is no optimistic lock, the value of the queue skipping thread will be overridden 
      }
      

2.2.10 Inquire about

  • adopt id Querying a single user

    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }
    
  • adopt id Querying multiple users

    @Test
    public void testSelectBatchIds(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
        users.forEach(System.out::println);
    }
    
  • Conditions of the query adopt map encapsulation

    @Test
    public void testMap(){
        HashMap<String, Object> map = new HashMap<>();
        // Customize the query 
        map.put("name","www");
        map.put("age",18);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
    
  • Paging query

    Pagination is used as much as ten times in websites !

    1、 The original limit Pagination

    2、PageHelper Third party plug-ins

    3、MybatisPlus In fact, it also has built-in paging plug-ins !

    Use steps :

    1. Configure interceptor components

      package com.mymall.config;
      
      import com.baomidou.mybatisplus.annotation.DbType;
      import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
      import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
      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;
      import org.springframework.transaction.annotation.EnableTransactionManagement;
      @Configuration
      @MapperScan("com.mymall.dao")
      @EnableTransactionManagement
      public class MybatisPlusConfig {
          @Bean
          public MybatisPlusInterceptor mybatisPlusInterceptor() {
              MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
              // Add optimistic lock 
              interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
              // New paging plug-in , One is to ease and the other to follow mybatis The rules of ,
              // Need to set up  MybatisConfiguration#useDeprecatedExecutor = false
              //  Avoid cache problems ( This property will be removed after the old plug-in is removed )
         // Or not DbType.MYSQL, If it is empty, it will pass URL Determine the database type      
              interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
              return interceptor;
          }
          @Bean
          public ConfigurationCustomizer configurationCustomizer() {
              return configuration -> configuration.setUseDeprecatedExecutor(false);
          }
      }
      
      
    2. Test paging query

      @Test
      public void testPage(){
          // Parameter one current: The current page     Parameter two size: Page size 
          // After using the paging plug-in , All paging operations have become simple 
          Page<User> page = new Page<>(2,5);
      	// The second parameter is the advanced query , Temporarily set to null  
          userMapper.selectPage(page,null);
          page.getRecords().forEach(System.out::println);
          System.out.println(" Total number of pages ==>"+page.getTotal());
      }
      

2.2.11 Delete

  • Basic delete operations

    @Test
    public void testDeleteById(){
        userMapper.deleteById(1);
    }
    @Test
    public void testDeleteBatchIds(){
      userMapper.deleteBatchIds(Arrays.asList(1,2));
    }
    @Test
    public void testD(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("age","18");
        map.put("name","lol");
        userMapper.deleteByMap(map);
    }
    
  • Logical deletion

    Physical delete : Delete directly from the database

    Logical deletion : Not deleted in the database , It's a variable that invalidates it ! deleted=0 ==> deleted=1

    Administrators can view deleted records ! Prevent data loss , It's like a recycle bin !

    Implementation steps :

    1. Add... To the database deleted Field

       deleted     int      default 0                 null comment ' Logical deletion :0 Show 1 Delete ',
      
    2. Add the configuration application.yml

      mybatis-plus:
        global-config:
          db-config:
            logic-delete-field: deleted  #  The name of the entity field for global logical deletion (since 3.3.0, After configuration, you can ignore the non configuration steps 2)
            logic-delete-value: 1 #  Logical deleted value ( The default is  1)
            logic-not-delete-value: 0 #  Logical undeleted value ( The default is  0)
      
    3. Add... To the entity class deleted Field and add @TableLogic annotation ( It's configured application.yml No comments can be added after , however deleted Fields must be added )

      @TableLogic
      private Integer deleted;
      
    4. Test whether the data still exists after deleting a piece of data , test result , It's just deleted Set up in order to 1

      @Test
      void testLogicDelete() {
          // Delete id by 2 The data of 
        int i = mpUserMapper.deleteById(2);
        MpUser mpUser = mpUserMapper.selectById(2);
        System.out.println(mpUser);
      }
      

 Insert picture description here

view the database , Found the record still ,deleted Turn into 1

 Insert picture description here
Test the deleted user again , The query was found to be empty
 Insert picture description here

2.2.12 Performance analysis plug-ins ( The new version has been removed )

In our usual development , There will be some slow Sql. test 、druid···

MybatisPlus Performance analysis plug-ins are also provided , If it exceeds this time, it stops running !

2.2.13 Conditional constructor wrapper

Warning :

Don't support and disapprove of in RPC Call the Wrapper transmitted

  1. wrapper It's heavy
  2. transmission wrapper It can be compared to your controller use map Receives the value ( Development fun , Maintenance of crematoria )
  3. Correct RPC Call pose is to write a DTO transmitted , The callee then uses DTO Perform the corresponding operation
  1. Commonly used api Please go to the web page to view Conditional constructor | MyBatis-Plus (baomidou.com)

  2. Examples of use

    • Query data that is not empty and larger than a certain value

      	@Test
        void testWrapper() {
          // The parameter is one wrapper , Conditional constructor , And just now map Comparative learning !
          // Inquire about username Not empty ,password Not empty ,user_id Greater than 18 Users of 
          // Notice the column The parameter must be the field name , Not a member variable in an entity class 
          QueryWrapper<MpUser> wrapper = new QueryWrapper<>();
          wrapper
                  .isNotNull("username")
                  .isNotNull("password")
                  .ge("user_id",2);
          List<MpUser> userList = mpUserMapper.selectList(wrapper);
          userList.forEach(System.out::println);
      }
      
    • Query the data whose field value is the determined value , The returned result has one or more possibilities

       @Test
      public void testWrapper2() {
          // Inquire about name=wsk Users of 
          QueryWrapper<MpUser> wrapper = new QueryWrapper<>();
          wrapper.eq("username","MPInsertTest1");
          // Query a data selectOne, If more than one is found, an error will be reported 
          //Expected one result (or null) to be returned by selectOne(), but found: *
          // If there are multiple results, use list or map
          MpUser mpUser = mpUserMapper.selectOne(wrapper);// Query a data , If there are multiple results, use list or map
          System.out.println(mpUser);
          List<MpUser> mpUsers = mpUserMapper.selectList(wrapper);
      }
      
    • Query the data whose field value range is in a certain range

      @Test
      public void testWrapper3() {
          // Inquire about age stay 10-20 Number of users between 
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper.between("age", 10, 20);// Section 
          Integer count = userMapper.selectCount(wrapper);// Number of output queries selectCount
          System.out.println(count);
      }
      
    • Fuzzy query ,notLike,likeRight,likeLeft

      @Test
      public void testWrapper4() {
          // Fuzzy query 
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper
              .notLike("name","s")
              .likeRight("email","t");//qq%   left and right ?
          List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
          maps.forEach(System.out::println);
      }
      
    • Subquery

      @Test
      public void testWrapper5() {
          // SELECT id,name,age,email,version,deleted,create_time,update_time 
          //FROM user 
          //WHERE deleted=0 AND id IN 
          //(select id from user where id<5)
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          //id  Find out in the subquery 
          wrapper.inSql("id","select id from user where id<5");
          List<Object> objects = userMapper.selectObjs(wrapper);
          objects.forEach(System.out::println);
      }
      
    • adopt id Sort

      @Test
      public void testWrapper6() {
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          // adopt id Sort in descending order 
          wrapper.orderByDesc("id");
          List<User> userList = userMapper.selectList(wrapper);
          userList.forEach(System.out::println);
      }
      

2.2.14 Code generator ,MP Reverse engineering

  • Add dependency

    MyBatis-Plus from 3.0.3 After that, the default dependency between code generator and template engine is removed , You need to manually add generator and template engine dependencies

    So let's try to use 3.5.1 edition ( The following tutorials apply only to 3.5.1 Above version , Incompatibility with historical versions )

    //  Be careful !! The current package does not pass dependencies  mp  package , Need to introduce 
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>Latest Version</version>
    </dependency>
    

    add to template engine rely on ,MyBatis-Plus Support Velocity( Default )、Freemarker、Beetl, Users can choose their own familiar template engine , If they don't meet your requirements , You can use a custom template engine . Here, according to the official documents freemarker

    Velocity( Default ):
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>latest-velocity-version</version>
    </dependency>
    
    Freemarker:
    <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.31</version>
    </dependency>
    
    Beetl:
    <dependency>
        <groupId>com.ibeetl</groupId>
        <artifactId>beetl</artifactId>
        <version>latest-beetl-version</version>
    </dependency>
    
  • stay mpper Create a code generator configuration class in a subproject

    package com.mymall;
    
    import com.baomidou.mybatisplus.generator.FastAutoGenerator;
    import com.baomidou.mybatisplus.generator.config.OutputFile;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    import java.util.Collections;
    
    /**
     * @author 18230
     * @version 1.0.0
     * @ClassName CodeGenerator.java
     * @Description
     * @createTime 2021 year 09 month 30 Japan  22:37:00
     */
    public class CodeGenerator {
        public static void main(String[] args) {
            /*
             *  url	jdbc route 	jdbc:mysql://127.0.0.1:3306/mybatis-plus
             *  username	 Database account 	root
             *  password	 Database password 	123456
             */
            FastAutoGenerator.create("jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true",
                    "root", "123456")
                    .globalConfig(builder -> {
                        builder.author("QC") //  Set the author 
                                .enableSwagger() //  Turn on  swagger  Pattern 
                                .fileOverride() //  Overwrite generated file 
                                // Prohibit opening Directory 
                                .disableOpenDir()
                                //  Specify output directory , The absolute path is used here 
                                .outputDir("F:\\JavaProjcet\\MyMallPractice2\\mapper\\src\\main\\java");
                        // If you use /src/main/java The file will be created in the root directory , That is, it didn't succeed 
                        // Source code :this.outputDir = System.getProperty("os.name").toLowerCase().contains("windows") ? "D://" : "/tmp";
                        //System.getProperty("os.name") Get the operating system name , If the name contains windows Just "D://" Otherwise, "/tmp"
                        // Judgment is windows System , Otherwise, it would be linux System , So you can only use absolute addresses 
                        //.outputDir("classpath:/src/main/java");
                    })
                    .packageConfig(builder -> {
                        builder.parent("com.mymall") //  Set the parent package name 
                                //.moduleName("mapper") //  Set the parent package module name , That is, add a package to the parent package name 
                                // But setting the relative path here succeeded once , But the root directory is generated later , So use the absolute path 
                                //.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "/src/main/resources/mapper")); //  Set up mapperXml Path is generated 
                                .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F:\\JavaProjcet\\MyMallPractice2\\mapper\\src\\main\\resources\\mapper")); //  Set up mapperXml Path is generated 
                    })
                    .strategyConfig(builder -> {
                        builder.addInclude("users") //  Set the table name to be generated 
                                .addInclude("category")
                                .addInclude("index_img")
                                .addInclude("mp_user")
                                .addInclude("product")
                                .addInclude("product_sku")
                                .addInclude("product_img")
                                .addInclude("orders")
                                .addInclude("product_comments")
                                .addInclude("product_params")
                                //.setEntityLombokModel(true)    // Turn on lombook Support , The new version is gone 
                                .addTablePrefix("mp_"); //  Set filter table prefix , That is, remove the prefix , Only the content facing back is retained as the entity name 
                    })
                    .templateEngine(new FreemarkerTemplateEngine()) //  Use Freemarker Engine templates , The default is Velocity Engine templates 
                    .execute();
        }
    }
    
    

    Generate successfully

image-20211001170639766image-20211001170639766image-20211001170639766image-20211001170639766image-20211001170639766image-20211001170639766

3 Solutions to common problems

3.1 database url Medium SSL problem

terms of settlement : take gerneratorConfig.xml Medium url Change to useSSL=false

connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&amp;serverTimezone=GMT%2b8"&amp;useUnicode=true&amp;characterEncoding=utf-8

3.2 Plug in not found

solve : adjustment mybatis-generator-maven-plugin edition

        <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>

3.3 All other tables in the database are generated

solve : stay gerneratorConfig.xml Just add the table name that needs to be generated

<table tableName="category" />

3.4 users Table generates other tables

image-20210906124200886

terms of settlement :

  1. Change my table name

  2. Try not to let MySql Keeping tables affects my Reverse Engineering

    Make sure that only your own specified database Medium User surface , In the first Medium connectionURL Specify the instance name of the database in , And then in Add related configuration information to , namely , You can ensure that only what you need User class .
    The configuration is as follows :

    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/xxx"
                            userId="xxx"
                            password="xxx">
                <property name="nullCatalogMeansCurrent" value="true"/>
            </jdbcConnection>
    

版权声明
本文为[QCTech]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/10/20211002145410632h.html

Scroll to Top