MyBatis-Plus Essential Features Guide
MyBatis-Plus is an enhanced toolkit built on top of MyBatis, providing powerful CRUD operations without modifying the original framework. It offers zero intrusion, minimal performance overhead, built-in CRUD functionality, Lambda expression support, code generation, pagination plugins, and multi-database compatibility.
Official Website: https://www.baomidou.comDocumentation: https://www.baomidou.com/introduce/
The MyBatisPlus team provides an official starter that bundles both MyBatis and MyBatisPlus features with auto-configuration capabilities. You can simply replace the MyBatis starter with the MyBatisPlus starter.
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>Latest Version</version>
</dependency>
- Quick Start
1.1 BaseMapper
Let's use a User table for demonstrating CRUD operations.
Create a custom Mapper interface that extends MyBatisPlus's BaseMapper interface with the entity class as the generic type. This interface provides pre-configured CRUD methods that can be used directly and won't conflict with any custom MyBatis methods you write.
public interface UserMapper extends BaseMapper<User> {
}
1.2 Key Annotations
MP scans entity classes and uses reflection to extract class information as database table metadata. The default mapping rules are:
- Convert class name from camelCase to snake_case for table names
- Fields named
idare treated as primary keys - Variable names are converted from camelCase to snake_case for column names
You can override these defaults using the following annotations:
@TableName: Specifies the exact table name@TableId: Marks and configures the primary key field withvaluefor column name andtypefor ID generation strategy AvailableIdTypeoptions:AUTO: Auto-increment in the databaseINPUT: Manually set via setter methodsASSIGN_ID: Assigned ID using the IdentifierGenerator interface's nextId method, with DefaultIdentifierGenerator (Snowflake algorithm) as the default implemantation
@TableField: Marks regular table columns Use this annotation in these scenarios:- When field names don't match database column names
- When field names start with "is" for Boolean types (MP strips "is" by default, so underscore must be added manually)
- When field names conflict with SQL reserved words (wrap with backticks)
- When a field isn't a database column (set
exist = false)
1.3 Common Configuration
MP configuration extends MyBatis native settings with its own specific options. Refer to official documentation for complete details.
mybatis-plus:
type-aliases-package: com.example.app.domain.entity
mapper-locations: "classpath*:/mapper/**/*.xml"
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
global-config:
db-config:
id-type: assign_id
update-strategy: not_null
1.4 Core Concepts
- POJO (Plain Ordinary Java Object): Simple Java objects that serve as intermediate layers. A POJO becomes a PO after persistence, a DTO during data transfer, and a VO when mapped to presentation layers.
- VO (View Object): Display-oriented objects that encapsulate all data for a specific page or component. When a DTO maps to a single VO, they're equivalent. When a DTO maps to multiple VOs, the presentation layer must convert VO data to DTO format before calling service layer methods, ensuring proper decoupling between layers.
- BO (Business Object): Objects that encapsulate business logic, potentially containing multiple other objects. For instance, a resume might contain education history, work experience, and social connections—each mapped to separate POs while a Resume BO coordinates them for business operations.
- DTO (Data Transfer Object): Used for remote calls and scenarios requiring bulk data transfer. If a database table has 100 fields but the UI only needs 10, transmitting a full PO would expose unnecessary structure. A DTO containing only those 10 fields solves this efficiently. When used for UI display, a DTO functions as a VO.
- DO (Domain Object): Business domain abstractions representing tangible or intangible entities. These serve as an abstraction layer between database and business logic, typically used in Service layers when accessing SQL. Commonly named xxxDO where xxx corresponds to the table name. DOs are a type of Entity with database mappings.
- PO (Persistent Object): Objects that directly map to persistence layer structures (typically relational databases). Each database record corresponds to a PO instance, enabling object-oriented manipulation of data records with easy conversion to other object types.
- Core Features
2.1 Query Wrappers
MyBatis-Plus provides various Wrapper classes for constructing complex WHERE conditions that cover virtually all query requirements in typical development.
2.1.1 QueryWrapper
QueryWrapper and LambdaQueryWrapper are primarily used for building WHERE clauses in SELECT, DELETE, and UPDATE statements.
【Example】Query Using QueryWrapper
SQL Statements
# Example 1: Find users with 'o' in their name, balance >= 1000, return id, username, info, balance
select id, username, info, balance
from user
where username like 'o' and balance >= 1000
# Example 2: Update balance to 2000 for user named 'jack'
update user
set balance = 2000
where (username = 'jack')
MP Implementation
/* Example 1: Query users matching criteria */
@Test
void testQueryWrapper1() {
QueryWrapper<User> queryConditions = new QueryWrapper<>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
List<User> result = userMapper.selectList(queryConditions);
result.forEach(System.out::println);
}
/* Example 2: Update specific user's balance */
@Test
void testQueryWrapper2() {
User targetUser = new User();
targetUser.setBalance(2000);
QueryWrapper<User> condition = new QueryWrapper<>().eq("username", "jack");
userMapper.update(targetUser, condition);
}
2.1.2 UpdateWrapper
UpdateWrapper and LambdaUpdateWrapper are useful when SET clause logic is complex or involves computed values.
【Example】Update Using UpdateWrapper
SQL Statement
# Example: Deduct 200 from balances of users with id 1, 2, or 4
update user
set balance = balance - 200
where id in (1, 2, 4)
MP Implementation
/* Example: Batch balance deduction */
@Test
void testUpdateWrapper() {
List<Long> targetIds = List.of(1L, 2L, 4L);
UpdateWrapper<User> modifier = new UpdateWrapper<>()
.setSql("balance = balance - 200")
.in("id", targetIds);
userMapper.update(null, modifier);
}
2.1.3 Lambda Query Wrappers
LambdaQueryWrapper and LambdaUpdateWrapper eliminate hardcoded column names by referencing entity class methods instead.
【Example】Refactoring Example 2.1.1 with Lambda Wrapper
/* Refactored testQueryWrapper1 */
LambdaQueryWrapper<User> conditions = new LambdaQueryWrapper<>()
.select(User::getId, User::getUsername, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
2.2 Custom SQL Statements
You can leverage MP's Wrapper classes to build complex WHERE conditions while writing the remaining SQL yourself.
【Example】Deduct specified amount from balances of users within given ID list (e.g., IDs 1, 2, 4)
Steps for MP Custom SQL:
- Build WHERE conditions using Wrapper
/* Service Layer */
/* customSqlSegment example */
List<Long> userIds = List.of(1L, 2L, 4L);
int deductionAmount = 200;
LambdaQueryWrapper<User> filter = new LambdaQueryWrapper<>().in(User::getId, userIds);
userMapper.deductBalance(filter, deductionAmount);
- Declare wrapper parameter with
@Paramannotation in mapper method (must be"ew"or useConstants.WRAPPER)
/* UserMapper.java */
void deductBalance(@Param("ew") LambdaQueryWrapper<User> filter, @Param("amount") int deductionAmount);
- Write custom SQL using Wrapper conditions
<update id="deductBalance">
update tb_user set balance = balance - #{amount} ${ew.customSqlSegment}
</update>
2.3 IService Interface
MP provides the Service layer with an IService interface and ServiceImpl implementation class.
2.3.1 Basic Usage
Your custom service interface should extend IService with your entity type, and your implementation class should extend ServiceImpl while implementing your custom interface.
/* UserService.java */
public interface UserService extends IService<User> {
}
/* UserServiceImpl.java */
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
2.3.2 CRUD Implementation Example
【Example】Implementing RESTful API endpoints
Add swagger (API documentation annotations) and web dependencies
<!-- swagger -->
<dependency>
<groupId>com.github.xiaoymins</groupId>
<artifactId>knife4j-openapi2-spring-boot-starters</artifactId>
<version>4.1.0</version>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configure swagger settings
# application.yaml
knife4j:
enable: true
openapi:
title: User Management API Documentation
description: "User Management API Documentation"
version: v1.0.0
group:
default:
group-name