Environment set up

  1. Creating a database

  1. Create the corresponding entity class User
  2. Import dependence
<dependencies>
    <! -- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.18</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.3.5. RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.3.5. RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Copy the code
  1. Configuration properties
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis_plus? useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
Copy the code
  1. Implementing an interface
//BaseMapper provides a series of basic operations by default
@Repository
public interface UserMapper extends BaseMapper<User> {}Copy the code
  1. Modifying the startup class
@SpringBootApplication
@MapperScan("com.mapper") // point to the package where the mapper is located
public class plus_01Application {
    public static void main(String[] args) { SpringApplication.run(plus_01Application.class,args); }}Copy the code
  1. To configure the log

Add the following code to the existing configuration file

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Copy the code

test

class DemoApplicationTests {
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads(a) {
        //List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
        //queryWrapper entity object encapsulates the operation class (can be null)
        //selectList queries based on the criteria passed in
        List<User> users = userMapper.selectList(null);
        for(User user:users) System.out.println(user); }}Copy the code

The results of

CRUD and expand

The insert

    @Test
    public void testInsert(a){
        User u=new User();
        u.setId(7);
        u.setEmail("baomidou.com");
        u.setName("jony");
        userMapper.insert(u);
    }
Copy the code

Primary key generation policy

Distributed system is a unique id generated: www.cnblogs.com/haoxinyue/p…

Snowflake algorithm:

Snowflake is Twitter’s open source distributed ID generation algorithm that results in a long ID. The idea is to use 41bits as the number of milliseconds, 10bits as the machine ID (5 bits for the data center, 5 bits for the machine ID), 12bits as the serial number within milliseconds (meaning each node can generate 4096 ids per millisecond), and finally a symbolic bit, always 0. The code can be found at github.com/twitter/sno…

public enum IdType {
    /** * Database ID increment * 

For this type, please ensure that the database ID increment is set otherwise it will not work

*/
AUTO(0), /** * This type is an unset primary key */ NONE(1), /** * The user enters ID *

this type can be filled by registering your own autofill plug-in

*/
INPUT(2), /* Only if the ID of the inserted object is empty, it will be automatically filled. * / /** * Assign ID (primary key type number or string), * default implementation class {@linkCom. Baomidou. Mybatisplus. Core. The incrementer. DefaultIdentifierGenerator} (snow algorithm) * *@since3.3.0 * / ASSIGN_ID(3), /** * Assign UUID (primary key type string) * default implementation class {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-","")) */ ASSIGN_UUID(4), / * * *@deprecated3.3.0 both please use {@link #ASSIGN_ID} */ @Deprecated ID_WORKER(3), / * * *@deprecated3.3.0 both please use {@link #ASSIGN_ID} */ @Deprecated ID_WORKER_STR(3), / * * *@deprecated3.3.0 both please use {@link #ASSIGN_UUID} */ @Deprecated UUID(4); private final int key; IdType(int key) { this.key = key; }}Copy the code
/*
     * 主键类型
     * {@link IdType}
    IdType type() default IdType.NONE;*/
// We specify the primary key generation method with @tableID. Setting the primary key increment needs to be set to increment in the database
    @TableId(type = IdType.AUTO)
    private int id;
Copy the code

The update operation

Update does not perform dynamic SQL, which is addressed at the end of this article

MybatisPlus will do the SQL concatenation for us automatically

    @Test
    public void testUpdate(a){
        User u=new User();
        u.setId(7);
        u.setEmail("@baomidou.com");
        // The argument is of object type
        //int updateById(@Param(Constants.ENTITY) T entity);
        userMapper.updateById(u);
    }
Copy the code

@Test
    public void testUpdate(a){
        User u=new User();
        u.setId(7);
        u.setName("hony");
        u.setEmail("@baomidou.com");
        userMapper.updateById(u);
    }
Copy the code

Automatic filling

Database level

Add two columns to the database

Modify the corresponding entity class

public class User {
    @TableId(type = IdType.AUTO)
    private int id;
    private Integer age;
    private String name;
    private String email;
    // Add the corresponding field
    private Date createTime;
    private Date updateTime;
}

Copy the code

Code level

  1. Add an annotation @tableField
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private int id;
    private Integer age;
    private String name;
    private String email;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE )
    private Date updateTime;
    @Version
    private Integer version;
}
Copy the code
 /** * field auto-fill strategy * 

* will ignore insertStrategy or updateStrategy configuration in the corresponding mode, equal to asserting that the field must have a value */

FieldFill fill(a) default FieldFill.DEFAULT; Copy the code
public enum FieldFill {
    /** ** does not process */ by default
    DEFAULT,
    /** * Fill in the field */ when inserting
    INSERT,
    /** * Fill in the field */ when updating
    UPDATE,
    /** * Fill the fields */ when inserting and updating
    INSERT_UPDATE
}

Copy the code
  1. Handling strategy
@Component // You need to register with the IOC container
public class MymetObejectHandler implements MetaObjectHandler {
// Insert policy
    @Override
    public void insertFill(MetaObject metaObject) {
      log.info("inserte fill start ---------");
                        // Database field, the populated value
      setFieldValByName("createTime".new Date(),metaObject) ;
      setFieldValByName("updateTime".new Date(),metaObject) ;
    }
// Update policy
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("update fill start ---------");
        setFieldValByName("updateTime".newDate(),metaObject) ; }}Copy the code

Optimistic locking

When a record is updated, it is hoped that the record has not been updated by others

Optimistic lock implementation:

  • When the record is fetched, the current version is retrieved
  • When you update, take this version with you
  • When performing an update, set version = newVersion where version = oldVersion
  • If the version is incorrect, the update fails
  1. Add the field version to the database

2. Update the entity class and add the corresponding attributes

@Version
private Integer version;
Copy the code
  1. Register with the IOC container
@Configuration
@MapperScan("com.mapper")
@EnableTransactionManagement // Enable transaction support
public class MyConfig {
    @Bean
    public MybatisPlusInterceptor optimisticLockerInterceptor(a){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        returninterceptor; }}Copy the code
  1. test
    @Test
    public void testop2(a){

        User u=userMapper.selectById(1);
        u.setEmail("t");
        User u2=userMapper.selectById(1);
        u2.setId(7);
        u2.setEmail("T2");
        userMapper.updateById(u2);
        userMapper.updateById(u);
    }
    // Email is changed to T2 instead of t
Copy the code

Query operation

    /** * query ** by ID@paramId Primary key ID */
    T selectById(Serializable id);
    / * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /    
     /** * query (by ID) **@paramIdList List of primary key ids (cannot be null or empty) */
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    / * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /   
    /** * Query (based on columnMap condition) **@paramColumnMap Table field map object */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Copy the code

The Map query is dynamically SQL based on the parameters we pass in

    @Test
    public void testSelect(a){
        // Query by id
        userMapper.selectById(1);
        // Batch query based on the array passed in
        userMapper.selectBatchIds(Arrays.asList(2.3.4));
        Map<String, Object> Map = new HashMap<>();
        Map.put("name"."jony");
        Map.put("age"."18");
        userMapper.selectByMap(Map);
    }
Copy the code

Paging query

Use the built-in paging plug-in of MybatisPlus for paging

  1. To register the plugin
public class MyConfig {
    @Bean
    public MybatisPlusInterceptor optimisticLockerInterceptor(a){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }}
Copy the code
  1. use
  /** * the paging constructor **@paramCurrent Current page *@paramSize Number of items displayed on a page */
    public Page(long current, long size) {
        this(current, size, 0);
    }
    / * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
     /** * Query all records according to entity condition **@paramPage paging query criteria (can be rowbound.default) *@paramThe queryWrapper entity object encapsulates the action class (which can be null) */
    <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Copy the code
 @Test
    public void testSelect(a){
    // 5 records to a page, display the second page
        Page<User> page = new Page<>(2.5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println );
    }

Copy the code

Delete operation

Similar to the above query operation


    /** * delete ** based on ID@paramId Primary key ID */
    int deleteById(Serializable id);
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
    /** * Drop the record ** according to the columnMap condition@paramColumnMap Table field map object */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /

    /** * delete (batch delete by ID) **@paramIdList List of primary key ids (cannot be null or empty) */
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
Copy the code
    @Test
    public void testDelete(a){
        userMapper.deleteById(8);
        userMapper.deleteBatchIds(Arrays.asList(2.3.4));
        Map<String, Object> Map = new HashMap<>();
        Map.put("name"."jony");
        Map.put("age"."18");
        userMapper.deleteByMap(Map);
    }
Copy the code

Logical deletion (only for automatically injected SQL)

  1. Add a field deleted (with a fixed name) in the database and set its default value to 0

2. Modify the entity class and add corresponding annotations

Note: Lower versions require components to be registered

 @Bean// Remove the component logically
    public ISqlInjector sqlInjector(a){
        return new LogicSqlInjector();
    }
Copy the code

  1. Modifying a Configuration File

Because our database sets deleted to 0 by default, we set logic-not-delete-value: 0 as the condition for not deleting. Logic-delete-value: 1 indicates the deleted flag.4. Test

When we delete user id 8, we are actually doing an update

Query user 8 again

Performance analysis plug-in

Mybatis-Plus removed PerformanceInterceptor in version 3.2 and above

  1. Import dependence

This plug-in has performance loss and is not recommended for production environments.

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>The latest version</version>
</dependency>
Copy the code
  1. Modify the original database properties
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    username: root
    password: 123456
    url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus? useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
Copy the code
  1. Add the configuration file spy.properties
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# Custom log printing
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
Log output to console
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
Use logging system to record SQL
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
P6spy Driver agent
deregisterdrivers=true
# remove the JDBC URL prefix
useprefix=true
# configuration record Log exceptions, can get rid of the result set of the error, the info of batch, debug, statement, commit, rollback, the result, the resultset.
excludecategories=info,debug,result,commit,resultset
# date format
dateformat=yyyy-MM-dd HH:mm:ss
# The actual driver can be multiple
#driverlist=org.h2.Driver
Whether to enable slow SQL recording
outagedetection=true
Slow SQL record standard 2 seconds
outagedetectioninterval=2
Copy the code

The conditional constructor Wrapper

Test 1 NotNull, lt

  @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // The mailbox is not empty 18 years old
    wrapper.isNotNull("name")
            .isNotNull("email")
            .lt("age".18);
    userMapper.selectList(wrapper);
}
Copy the code

Test 2 eq

  @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name"."jony");
    userMapper.selectOne(wrapper);
}
Copy the code

Test 3 between

 @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age".18.20);
    userMapper.selectCount(wrapper);
}
Copy the code

Test 4 Like fuzzy query

 @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.notLike("name"."j")//%j%
            .likeLeft("email"."t");// %t
    userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code

Test 5 subqueries

 @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id"."select id from user where age>18");
    userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code

Test 6 Sorting

 @Test
    public void TestWrapper(a){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    / / Desc descending order
     wrapper.orderByDesc("id");
    userMapper.selectList(wrapper).forEach(System.out::println);
}
Copy the code

Code generator

  1. Import dependence

MyBatis-Plus removed the default dependencies between code generators and template engines after 3.0.3, requiring manual addition of dependencies:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.2</version>
</dependency>// Template engine dependency, which can be changed, after which you need to set the template engine in AutoGenerator<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>
Copy the code
  1. Write the code
    @Test
    public void auto(a){
        AutoGenerator mpg=new AutoGenerator();
        // Global configuration
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");// Set the output address
        globalConfig.setAuthor("lin");// Set the author
        globalConfig.setOpen(false);// Set whether to open the folder after the build
        globalConfig.setFileOverride(false);// Whether to override
        globalConfig.setServiceName("%sService");// Remove the I prefix of service
        globalConfig.setIdType(IdType.ASSIGN_ID);// Specify the ID type of the generated primary key
        globalConfig.setDateType(DateType.ONLY_DATE);// Use only java.util. Date instead
        globalConfig.setSwagger2(true);/ / use swagger
        mpg.setGlobalConfig(globalConfig);

        // Configure the database
    DataSourceConfig dataSourceConfig = new DataSourceConfig();
    dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis_plus? useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");
    dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
    dataSourceConfig.setUsername("root");
    dataSourceConfig.setPassword("123456");
    dataSourceConfig.setDbType(DbType.MYSQL);
    mpg.setDataSource(dataSourceConfig);

    / / package Settings
    PackageConfig packageConfig = new PackageConfig();
    packageConfig.setModuleName("blog");
    packageConfig.setParent("com");
    packageConfig.setEntity("entity");
    packageConfig.setService("service");
    packageConfig.setMapper("mapper");
    packageConfig.setController("controller");
    mpg.setPackageInfo(packageConfig);
    // Policy configuration
    StrategyConfig strategyConfig = new StrategyConfig();
    strategyConfig.setInclude("user");// Set the table name for the mapping
    strategyConfig.setNaming(NamingStrategy.underline_to_camel);// Underline the hump name
    strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);// Underline the hump name
    strategyConfig.setSuperEntityClass("Specify the parent entity");// Specify the inherited parent class
    strategyConfig.setEntityLombokModel(true);/ / Lombok automatically
    strategyConfig.setRestControllerStyle(true);/ / a restful style
    strategyConfig.setLogicDeleteFieldName("deleted");// Set the logical delete field
    // Auto-fill
    TableFill gmtCreat=new TableFill("gmt_creat", FieldFill.INSERT);// Field, condition
    TableFill gmtModified=new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
    ArrayList<TableFill> arrayList= new ArrayList<>();
    arrayList.add(gmtCreat);
    arrayList.add(gmtModified);
    strategyConfig.setTableFillList(arrayList);
    / / optimistic locking
    strategyConfig.setVersionFieldName("version");// Specify a field
    / / hump hyphen/managerUserActionHistory - > / manager - user - action - history
    strategyConfig.setControllerMappingHyphenStyle(true);
    strategyConfig.setRestControllerStyle(true);/ / open Restful

    mpg.setStrategy(strategyConfig);
    mpg.execute();
}
Copy the code

Test results:

debug

1. Update does not perform dynamic SQL

The reason:

  1. Int is the base data type and Integer is the reference data type.

  2. Ingeter is a wrapper for int, whose initial value is 0 and whose initial value is null.

The number in the object is defined as an int and defaults to 0 if no value is assigned, and then MyBatisPlus assumes that you assigned a value of 0 to update it instead of dynamically concatenating SQL.