Master MyBatis-Plus: From Basics to Advanced CRUD, Pagination, and Code Generation

This comprehensive guide walks you through MyBatis-Plus fundamentals, non‑intrusive features, quick project setup, CRUD operations, automatic field filling, optimistic and logical locking, powerful wrapper queries, pagination, and the built‑in code generator, all illustrated with runnable examples and code snippets.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Master MyBatis-Plus: From Basics to Advanced CRUD, Pagination, and Code Generation

Introduction

MyBatis‑Plus (MP) is an enhancement library for MyBatis that adds a rich set of features without modifying the core framework. It aims to reduce boilerplate code, simplify CRUD operations, and improve development efficiency in Spring Boot projects.

Key Features

Non‑intrusive : integrates by adding a starter dependency; existing MyBatis code continues to work unchanged.

Low overhead : basic CRUD methods are injected at runtime with negligible performance impact.

Generic CRUD : BaseMapper and BaseService provide most single‑table operations out‑of‑the‑box.

Lambda query : type‑safe query construction using Java lambda expressions.

Primary‑key strategies : four built‑in ID generators (AUTO, INPUT, ID_WORKER, UUID) and a distributed Snowflake implementation.

ActiveRecord : entities can extend Model to call CRUD methods directly.

Global method injection : utilities such as saveBatch, removeById are available everywhere.

Code generator : Maven plugin or programmatic AutoGenerator can scaffold entity, mapper, service and controller classes.

Pagination plugin : supports MySQL, PostgreSQL, Oracle, SQLServer and many other databases.

Performance analysis : logs executed SQL and execution time.

Global interceptors : logical delete, optimistic lock and safe‑delete protection.

Quick Start

1. Create the database

Execute the following DDL/DML script in MySQL to create a database mybatis_plus and a user table with sample data.

DROP TABLE IF EXISTS user;

CREATE TABLE user (
  id BIGINT(20) NOT NULL COMMENT 'Primary Key',
  name VARCHAR(30) NULL DEFAULT NULL COMMENT 'Name',
  age INT(11) NULL DEFAULT NULL COMMENT 'Age',
  email VARCHAR(50) NULL DEFAULT NULL COMMENT 'Email',
  PRIMARY KEY (id)
);

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');

2. Create a Maven project

Add the following dependencies to pom.xml. The starter mybatis-plus-boot-starter must not be used together with the original MyBatis starter.

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.3.1</version>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>

3. Application configuration

Configure the datasource and enable MyBatis‑Plus logging in src/main/resources/application.yml:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

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

4. Write the code

Create the entity, mapper and the Spring Boot entry point.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

// Mapper extends the generic BaseMapper provided by MP
public interface UserMapper extends BaseMapper<User> {}

@SpringBootApplication
@MapperScan("com.ly.mapper") // adjust the package to your project
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}

CRUD Operations

Insert

@Test
public void testInsert() {
    User user = new User();
    user.setName("LY");
    user.setAge(100);
    user.setEmail("[email protected]");
    int rows = userMapper.insert(user); // ID is auto‑filled
    System.out.println("Affected rows: " + rows);
    System.out.println("Generated ID: " + user.getId());
}

Update

@Test
public void testUpdate() {
    User user = new User();
    user.setId(3L);
    user.setName("ZZ");
    user.setAge(50);
    userMapper.updateById(user);
}

Delete

@Test
public void testDeleteById() {
    userMapper.deleteById(1L);
}

Select

@Test
public void testSelectById() {
    User user = userMapper.selectById(1L);
    System.out.println(user);
}

Automatic Field Filling

Define timestamp columns in the table and annotate the entity fields with @TableField(fill = FieldFill.INSERT) or FieldFill.INSERT_UPDATE. Implement a MetaObjectHandler to populate the values.

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

Optimistic Lock

Add a version field annotated with @Version and register the OptimisticLockerInterceptor bean.

public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Integer version;
    // getters & setters omitted
}

@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

When updateById is called, MP adds WHERE version = ?. If another transaction has already updated the row, the version mismatch prevents the update, achieving optimistic concurrency control.

Logical Delete

Add a column (e.g., deleted) to the table and annotate the entity field with @TableLogic. Configure global values in application.yml so that MP automatically adds WHERE deleted = 0 to queries and sets deleted = 1 on delete.

public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    private Integer deleted;
}

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0

Wrapper (Condition Builder) Queries

MP provides QueryWrapper and LambdaQueryWrapper for building type‑safe conditions.

Non‑null name and email, age ≥ 35:

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
       .isNotNull("email")
       .ge("age", 35);
List<User> list = userMapper.selectList(wrapper);

Exact name match:

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "LY");
User user = userMapper.selectOne(wrapper);

Age between 10 and 30:

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 10, 30);
int count = userMapper.selectCount(wrapper);

Fuzzy search (not like & like left):

wrapper.notLike("name", "Z")
       .likeLeft("email", "@qq.com");
List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);

Sub‑query:

wrapper.inSql("id", "select id from user where id < 5");
List<Object> ids = userMapper.selectObjs(wrapper);

Order by ID ascending:

wrapper.orderByAsc("id");
List<User> users = userMapper.selectList(wrapper);

Pagination

Register the pagination interceptor and use Page<T> to retrieve a specific page.

@Bean
public PaginationInterceptor paginationInterceptor() {
    PaginationInterceptor pi = new PaginationInterceptor();
    pi.setCountSqlParser(new JsqlParserCountOptimize(true)); // join count optimization
    return pi;
}

@Test
public void testPage() {
    Page<User> page = new Page<>(2, 5); // page 2, 5 records per page
    IPage<User> result = userMapper.selectPage(page, null);
    result.getRecords().forEach(System.out::println);
    System.out.println("Total records: " + result.getTotal());
}

Code Generator

The AutoGenerator can generate entity, mapper, service and controller classes based on the database schema. A typical configuration includes global settings, datasource, package layout and strategy (naming, Lombok, logic‑delete, auto‑fill, optimistic lock, REST style).

public class MyBatisPlusGenerator {
    public static void main(String[] args) {
        AutoGenerator mpg = new AutoGenerator();

        // 1. Global config
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("AuthorName");
        gc.setOpen(false);
        gc.setServiceName("%sService");
        gc.setIdType(IdType.AUTO);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 2. Data source config
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 3. Package config
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.ly");
        pc.setModuleName("blog");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 4. Strategy config
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user"); // tables to generate
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setLogicDeleteFieldName("deleted");
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
        strategy.setTableFillList(java.util.Arrays.asList(gmtCreate, gmtModified));
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);

        // 5. Execute generation
        mpg.execute();
    }
}

Conclusion

MyBatis‑Plus dramatically reduces the amount of repetitive code required for MyBatis projects. It supplies ready‑made CRUD methods, a powerful condition builder, automatic field handling (timestamps, version, logical delete), built‑in pagination, and a code generator, making it a practical choice for Spring Boot back‑end development.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaCode GenerationSpring Bootpaginationoptimistic lockmybatis-plusCRUDLogical Delete
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.