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

QCTech 2021-10-14 05:07:52

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("[email protected]");
    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>
    
Please bring the original link to reprint ,thank
Similar articles

2021-10-14