Master MyBatis-Plus with Spring Boot: From Setup to Advanced Features

This guide walks through setting up a MySQL database, configuring a Spring Boot project with MyBatis‑Plus, defining entities and mappers, and demonstrates CRUD operations, pagination, logical and physical deletes, optimistic locking, performance monitoring, and code generation, providing complete code snippets and configuration details.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Master MyBatis-Plus with Spring Boot: From Setup to Advanced Features

Database and Table Creation

Create a MySQL database named mybatis_plus and a user table with the columns id, name, age and email. In production you would typically also add version, deleted, gmt_create and gmt_modified fields.

DROP TABLE IF EXISTS user;
CREATE TABLE user (
  id BIGINT(20) NOT NULL COMMENT 'Primary key ID',
  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)
);
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]');

Spring Boot Project Initialization

Generate a Spring Boot project (e.g., via Spring Initializr) and add the following Maven dependencies:

<!-- MySQL driver -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- Lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>

<!-- MyBatis‑Plus starter (3.x) -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.0.5</version>
</dependency>

Do not import the original MyBatis starter together with MyBatis‑Plus to avoid version conflicts.

Database Connection Configuration

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

Domain Model

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

Mapper Interface

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

@Repository
public interface UserMapper extends BaseMapper<User> {
    // All CRUD methods are inherited from BaseMapper
}

Enable mapper scanning in the main application class, e.g. @MapperScan("com.kwhua.mapper").

Integration Test Example

@SpringBootTest
public class MybatisPlusApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        // Query all records
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

SQL Logging

Make MyBatis‑Plus output the executed SQL statements:

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

CRUD Operations

Insert

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

Primary‑Key Generation Strategies

Supported IdType values (excerpt):

public enum IdType {
    AUTO(0),        // Database auto‑increment
    NONE(1),        // No primary key
    INPUT(2),       // Manually supplied
    ID_WORKER(3),   // Global unique ID (default)
    UUID(4),        // UUID string
    ID_WORKER_STR(5);
}

Update

@Test
public void testUpdate() {
    User user = new User();
    user.setId(1302223874217295874L);
    user.setName("kwhua_mybatis-plus_updateTest");
    user.setAge(20);
    int rows = userMapper.updateById(user);
    System.out.println("Updated rows: " + rows);
}

Query

// By primary key
User user = userMapper.selectById(1L);

// Batch query by IDs
List<User> list = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));

// Conditional query using a map
Map<String, Object> map = new HashMap<>();
map.put("name", "kwhua");
map.put("age", 15);
List<User> result = userMapper.selectByMap(map);

Physical Delete

userMapper.deleteById(1L);
userMapper.deleteBatchIds(Arrays.asList(2L, 3L));
Map<String, Object> delMap = new HashMap<>();
delMap.put("name", "kwhua");
userMapper.deleteByMap(delMap);

Logical Delete

Add a deleted column to the table and the entity, annotate the field with @TableLogic, and configure the global logic‑delete values.

// Entity field
@TableLogic
private Integer deleted;

// Bean registration
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

// application.yml fragment
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0

Performance Analysis Plugin

Log each SQL statement and its execution time (useful in dev or test profiles).

@Bean
@Profile({"dev", "test"})
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor pi = new PerformanceInterceptor();
    pi.setMaxTime(100); // ms
    pi.setFormat(true);
    return pi;
}

Condition Builder (Wrapper)

// Example: name and email not null, age >= 18
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
       .isNotNull("email")
       .ge("age", 18);
userMapper.selectList(wrapper).forEach(System.out::println);

// Exact match on name
QueryWrapper<User> eq = new QueryWrapper<>();
eq.eq("name", "kwhua");
User u = userMapper.selectOne(eq);
System.out.println(u);

Code Generator

MyBatis‑Plus can generate entity, mapper, service and controller classes from database tables.

public class GenerateCode {
    public static void main(String[] args) {
        AutoGenerator mpg = new AutoGenerator();
        // Global configuration
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("kwhua");
        gc.setOpen(false);
        gc.setFileOverride(false);
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        gc.setServiceName("%sService");
        gc.setControllerName("%sController");
        gc.setServiceImplName("%sServiceImpl");
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        mpg.setGlobalConfig(gc);
        // Data source configuration
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/kwhua_test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        // Package configuration
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.kwhua");
        pc.setModuleName("model");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);
        // Strategy configuration
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user", "course");
        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(Arrays.asList(gmtCreate, gmtModified));
        strategy.setVersionFieldName("version");
        strategy.setTablePrefix("t_");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        // Execute generation
        mpg.execute();
    }
}

Optimistic Locking

Add a version column to the table and the entity, annotate it with @Version, and register the interceptor.

// Entity field
@Version
private Integer version;

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

When updating, MyBatis‑Plus automatically adds WHERE version = ?. If the version has changed, the update fails, preventing lost updates.

Pagination

// Register pagination interceptor
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

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

Automatic Timestamp Filling

Define gmt_create and gmt_modified columns and annotate the entity fields with @TableField(fill = FieldFill.INSERT) or FieldFill.INSERT_UPDATE. Implement a MetaObjectHandler to set the values.

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

Summary

This guide demonstrates how to set up MyBatis‑Plus in a Spring Boot project, configure the data source, define domain entities and mappers, enable SQL logging, and perform full CRUD operations—including insert, update, query, physical delete, logical delete, optimistic locking, pagination, performance monitoring, and code generation. The provided code snippets can be copied directly into a Spring Boot application to get a working MyBatis‑Plus integration.

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 Bootoptimistic 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.