MyBatis-Plus is an enhanced toolkit for MyBatis providing CRUD operations, query wrappers, pagination, code generation, and Spring Boot integration.
—
MyBatis-Plus provides comprehensive annotation support for mapping Java entities to database tables, with flexible configuration options for table names, column mapping, primary key strategies, field validation, and special column handling.
Maps entity class to database table with schema and naming customization.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
/**
* Table name (default: class name converted to underscore)
*/
String value() default "";
/**
* Schema name
*/
String schema() default "";
/**
* Whether to keep global table prefix
*/
boolean keepGlobalPrefix() default false;
/**
* Custom result map name
*/
String resultMap() default "";
/**
* Whether to auto-build result map
*/
boolean autoResultMap() default false;
/**
* Exclude properties from automatic mapping
*/
String[] excludeProperty() default {};
}Configures primary key field mapping and generation strategy.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableId {
/**
* Column name (default: field name converted to underscore)
*/
String value() default "";
/**
* Primary key generation type
*/
IdType type() default IdType.NONE;
}Configures field-to-column mapping with advanced options.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableField {
/**
* Column name (default: field name converted to underscore)
*/
String value() default "";
/**
* Whether field exists in database table
*/
boolean exist() default true;
/**
* Custom condition for WHERE clause
*/
String condition() default "";
/**
* Custom update value
*/
String update() default "";
/**
* Insert strategy for field
*/
FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
/**
* Update strategy for field
*/
FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
/**
* WHERE condition strategy for field
*/
FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
/**
* Auto-fill strategy
*/
FieldFill fill() default FieldFill.DEFAULT;
/**
* Whether to include in SELECT queries
*/
boolean select() default true;
/**
* Whether to keep global column format
*/
boolean keepGlobalFormat() default false;
/**
* JDBC type for this field
*/
JdbcType jdbcType() default JdbcType.UNDEFINED;
/**
* Type handler class for this field
*/
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
/**
* Numeric scale for decimal types
*/
String numericScale() default "";
}Marks field for optimistic locking version control.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Version {
}Configures logical delete functionality.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableLogic {
/**
* Logical not deleted value (default: "")
*/
String value() default "";
/**
* Logical deleted value (default: "")
*/
String delval() default "";
}Marks enum field value to be stored in database.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumValue {
}Configures sequence-based key generation for Oracle, PostgreSQL, etc.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface KeySequence {
/**
* Sequence name
*/
String value() default "";
/**
* Database type
*/
DbType dbType() default DbType.OTHER;
}Configures default ordering for entity queries.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OrderBy {
/**
* Whether to order ascending (default: true)
*/
boolean asc() default true;
/**
* Sort priority (smaller values have higher priority)
*/
short sort() default Short.MAX_VALUE;
}Controls which interceptors to ignore for specific mapper methods.
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface InterceptorIgnore {
/**
* Ignore tenant line interceptor
*/
boolean tenantLine() default false;
/**
* Ignore dynamic table name interceptor
*/
boolean dynamicTableName() default false;
/**
* Ignore block attack interceptor
*/
boolean blockAttack() default false;
/**
* Ignore illegal SQL interceptor
*/
boolean illegalSql() default false;
/**
* Ignore data permission interceptor
*/
boolean dataPermission() default false;
}Primary key generation strategies.
public enum IdType {
/**
* Database auto-increment
*/
AUTO(0),
/**
* No primary key (used for views or tables without primary key)
*/
NONE(1),
/**
* User input ID (manual assignment)
*/
INPUT(2),
/**
* Assign ID using snowflake algorithm
*/
ASSIGN_ID(3),
/**
* Assign UUID
*/
ASSIGN_UUID(4);
}Auto-fill strategies for fields.
public enum FieldFill {
/**
* Default - no auto-fill
*/
DEFAULT,
/**
* Fill on insert operations
*/
INSERT,
/**
* Fill on update operations
*/
UPDATE,
/**
* Fill on both insert and update operations
*/
INSERT_UPDATE;
}Field condition strategies for query building.
public enum FieldStrategy {
/**
* Ignore validation (always include in conditions)
*/
IGNORED,
/**
* Ignore null values only
*/
NOT_NULL,
/**
* Ignore null and empty values
*/
NOT_EMPTY,
/**
* Use global default strategy
*/
DEFAULT,
/**
* Never include in conditions (used for read-only fields)
*/
NEVER;
}Basic Entity Mapping:
@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("user_name")
private String name;
private Integer age;
@TableField("email_address")
private String email;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
// getters and setters...
}Advanced Field Configuration:
@TableName("product")
public class Product {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
@TableField(value = "price_amount", jdbcType = JdbcType.DECIMAL, numericScale = "2")
private BigDecimal price;
@TableField(insertStrategy = FieldStrategy.NOT_EMPTY, updateStrategy = FieldStrategy.NOT_NULL)
private String description;
@TableField(exist = false) // Not a database column
private String displayName;
@TableField(select = false) // Exclude from SELECT queries by default
private String internalNotes;
@TableLogic
private Integer deleted; // 0 = not deleted, 1 = deleted
@Version
private Integer version; // For optimistic locking
// getters and setters...
}Enum Handling:
public enum UserStatus {
ACTIVE(1, "Active"),
INACTIVE(0, "Inactive"),
SUSPENDED(-1, "Suspended");
@EnumValue // This field will be stored in database
private final int code;
private final String description;
UserStatus(int code, String description) {
this.code = code;
this.description = description;
}
// getters...
}
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private UserStatus status; // Will store code (1, 0, -1) in database
// getters and setters...
}Auto-Fill Configuration:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "createUser", String.class, getCurrentUser());
this.strictInsertFill(metaObject, "updateUser", String.class, getCurrentUser());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser());
}
private String getCurrentUser() {
// Get current user from security context
return "system"; // Placeholder
}
}
// Entity with auto-fill fields
@TableName("audit_entity")
public class AuditEntity {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private String createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateUser;
// getters and setters...
}Schema and Naming Configuration:
@TableName(value = "user_profile", schema = "auth")
public class UserProfile {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("first_name")
private String firstName;
@TableField("last_name")
private String lastName;
// Maps to column: auth.user_profile.first_name, auth.user_profile.last_name
// getters and setters...
}Custom Type Handlers:
public class JsonTypeHandler extends AbstractJsonTypeHandler<List<String>> {
@Override
protected List<String> parse(String json) {
return JSON.parseArray(json, String.class);
}
@Override
protected String toJson(List<String> obj) {
return JSON.toJSONString(obj);
}
}
@TableName("user_preferences")
public class UserPreferences {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(typeHandler = JsonTypeHandler.class)
private List<String> tags; // Stored as JSON string in database
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> settings; // Stored as JSON using Jackson
// getters and setters...
}Sequence-Based Primary Keys:
@TableName("oracle_entity")
@KeySequence(value = "SEQ_ORACLE_ENTITY", dbType = DbType.ORACLE)
public class OracleEntity {
@TableId(type = IdType.INPUT) // Use INPUT for sequence-generated IDs
private Long id;
private String name;
// getters and setters...
}
@TableName("postgres_entity")
@KeySequence(value = "postgres_entity_id_seq", dbType = DbType.POSTGRE_SQL)
public class PostgresEntity {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
// getters and setters...
}Interceptor Control:
@Mapper
public interface UserMapper extends BaseMapper<User> {
@InterceptorIgnore(tenantLine = true, dataPermission = true)
List<User> selectAllUsers();
@InterceptorIgnore(blockAttack = true)
int deleteAllTestUsers();
}Complex Entity Example:
@TableName(value = "complex_entity", resultMap = "complexEntityResultMap")
public class ComplexEntity {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@TableField(condition = SqlCondition.LIKE)
private String name;
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String code;
@TableField(whereStrategy = FieldStrategy.NOT_EMPTY)
private String description;
@TableField(update = "now()")
private LocalDateTime lastModified;
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
@Version
private Integer version;
@OrderBy(asc = false, sort = 1)
private LocalDateTime createTime;
@OrderBy(asc = true, sort = 2)
private String name;
@TableField(exist = false)
private List<String> tags; // Calculated field, not in database
// getters and setters...
}Global Configuration:
@Configuration
public class MybatisPlusConfig {
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
// Global ID strategy
dbConfig.setIdType(IdType.ASSIGN_ID);
// Global table prefix
dbConfig.setTablePrefix("t_");
// Global logical delete configuration
dbConfig.setLogicDeleteField("is_deleted");
dbConfig.setLogicDeleteValue("1");
dbConfig.setLogicNotDeleteValue("0");
// Global field strategies
dbConfig.setInsertStrategy(FieldStrategy.NOT_NULL);
dbConfig.setUpdateStrategy(FieldStrategy.NOT_NULL);
dbConfig.setWhereStrategy(FieldStrategy.NOT_EMPTY);
// Column naming strategy
dbConfig.setTableUnderline(true);
dbConfig.setColumnUnderline(true);
globalConfig.setDbConfig(dbConfig);
return globalConfig;
}
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MyMetaObjectHandler();
}
}This annotation system provides flexible and powerful entity mapping capabilities while maintaining clean separation between Java objects and database schemas.
Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus