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.
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.StdOutImpl4. 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: 0Wrapper (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.
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.
