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.
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: rootDomain 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.StdOutImplCRUD 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: 0Performance 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
