MyBatis-Plus is an enhanced toolkit for MyBatis providing CRUD operations, query wrappers, pagination, code generation, and Spring Boot integration.
—
MyBatis-Plus provides flexible query wrapper classes for building complex SQL queries with both string-based and lambda-style condition APIs, supporting all common SQL operations with type safety and fluent interfaces.
String-based query wrapper for building SQL conditions using column names.
/**
* Query wrapper for building SQL conditions with column names
* @param <T> Entity type
*/
public class QueryWrapper<T> extends AbstractWrapper<T, String, QueryWrapper<T>>
implements Query<QueryWrapper<T>, T, String> {
// Equality conditions
public QueryWrapper<T> eq(String column, Object val);
public QueryWrapper<T> ne(String column, Object val);
// Comparison conditions
public QueryWrapper<T> gt(String column, Object val);
public QueryWrapper<T> ge(String column, Object val);
public QueryWrapper<T> lt(String column, Object val);
public QueryWrapper<T> le(String column, Object val);
// Range conditions
public QueryWrapper<T> between(String column, Object val1, Object val2);
public QueryWrapper<T> notBetween(String column, Object val1, Object val2);
// String matching conditions
public QueryWrapper<T> like(String column, Object val);
public QueryWrapper<T> notLike(String column, Object val);
public QueryWrapper<T> likeLeft(String column, Object val);
public QueryWrapper<T> likeRight(String column, Object val);
// Null conditions
public QueryWrapper<T> isNull(String column);
public QueryWrapper<T> isNotNull(String column);
// Collection conditions
public QueryWrapper<T> in(String column, Collection<?> values);
public QueryWrapper<T> notIn(String column, Collection<?> values);
public QueryWrapper<T> in(String column, Object... values);
public QueryWrapper<T> notIn(String column, Object... values);
// Subquery conditions
public QueryWrapper<T> inSql(String column, String inValue);
public QueryWrapper<T> notInSql(String column, String notInValue);
// Grouping and ordering
public QueryWrapper<T> groupBy(String... columns);
public QueryWrapper<T> orderByAsc(String... columns);
public QueryWrapper<T> orderByDesc(String... columns);
public QueryWrapper<T> orderBy(boolean condition, boolean isAsc, String... columns);
// Having clause
public QueryWrapper<T> having(String sqlHaving, Object... params);
// Logical operators
public QueryWrapper<T> or();
public QueryWrapper<T> or(boolean condition);
public QueryWrapper<T> and(Consumer<QueryWrapper<T>> function);
public QueryWrapper<T> or(Consumer<QueryWrapper<T>> function);
// Nested conditions
public QueryWrapper<T> nested(Consumer<QueryWrapper<T>> function);
// Custom SQL
public QueryWrapper<T> apply(String applySql, Object... values);
public QueryWrapper<T> last(String lastSql);
// Existence conditions
public QueryWrapper<T> exists(String existsSql);
public QueryWrapper<T> notExists(String notExistsSql);
// Lambda conversion
public LambdaQueryWrapper<T> lambda();
// Column selection
public QueryWrapper<T> select(String... sqlSelect);
public QueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate);
}Lambda-style query wrapper providing type-safe property references using method references.
/**
* Lambda query wrapper for type-safe property references
* @param <T> Entity type
*/
public class LambdaQueryWrapper<T> extends AbstractLambdaWrapper<T, LambdaQueryWrapper<T>>
implements Query<LambdaQueryWrapper<T>, T, SFunction<T, ?>> {
// Equality conditions
public LambdaQueryWrapper<T> eq(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> ne(SFunction<T, ?> fn, Object val);
// Comparison conditions
public LambdaQueryWrapper<T> gt(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> ge(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> lt(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> le(SFunction<T, ?> fn, Object val);
// Range conditions
public LambdaQueryWrapper<T> between(SFunction<T, ?> fn, Object val1, Object val2);
public LambdaQueryWrapper<T> notBetween(SFunction<T, ?> fn, Object val1, Object val2);
// String matching conditions
public LambdaQueryWrapper<T> like(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> notLike(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> likeLeft(SFunction<T, ?> fn, Object val);
public LambdaQueryWrapper<T> likeRight(SFunction<T, ?> fn, Object val);
// Null conditions
public LambdaQueryWrapper<T> isNull(SFunction<T, ?> fn);
public LambdaQueryWrapper<T> isNotNull(SFunction<T, ?> fn);
// Collection conditions
public LambdaQueryWrapper<T> in(SFunction<T, ?> fn, Collection<?> values);
public LambdaQueryWrapper<T> notIn(SFunction<T, ?> fn, Collection<?> values);
public LambdaQueryWrapper<T> in(SFunction<T, ?> fn, Object... values);
public LambdaQueryWrapper<T> notIn(SFunction<T, ?> fn, Object... values);
// Subquery conditions
public LambdaQueryWrapper<T> inSql(SFunction<T, ?> fn, String inValue);
public LambdaQueryWrapper<T> notInSql(SFunction<T, ?> fn, String notInValue);
// Grouping and ordering
public LambdaQueryWrapper<T> groupBy(SFunction<T, ?>... fns);
public LambdaQueryWrapper<T> orderByAsc(SFunction<T, ?>... fns);
public LambdaQueryWrapper<T> orderByDesc(SFunction<T, ?>... fns);
public LambdaQueryWrapper<T> orderBy(boolean condition, boolean isAsc, SFunction<T, ?>... fns);
// Having clause
public LambdaQueryWrapper<T> having(String sqlHaving, Object... params);
// Logical operators
public LambdaQueryWrapper<T> or();
public LambdaQueryWrapper<T> or(boolean condition);
public LambdaQueryWrapper<T> and(Consumer<LambdaQueryWrapper<T>> function);
public LambdaQueryWrapper<T> or(Consumer<LambdaQueryWrapper<T>> function);
// Nested conditions
public LambdaQueryWrapper<T> nested(Consumer<LambdaQueryWrapper<T>> function);
// Custom SQL
public LambdaQueryWrapper<T> apply(String applySql, Object... values);
public LambdaQueryWrapper<T> last(String lastSql);
// Existence conditions
public LambdaQueryWrapper<T> exists(String existsSql);
public LambdaQueryWrapper<T> notExists(String notExistsSql);
// Column selection
public LambdaQueryWrapper<T> select(SFunction<T, ?>... fns);
public LambdaQueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate);
}String-based update wrapper for building update statements with WHERE conditions.
/**
* Update wrapper for building update statements with column names
* @param <T> Entity type
*/
public class UpdateWrapper<T> extends AbstractWrapper<T, String, UpdateWrapper<T>>
implements Update<UpdateWrapper<T>, String> {
// Set operations
public UpdateWrapper<T> set(String column, Object val);
public UpdateWrapper<T> set(boolean condition, String column, Object val);
public UpdateWrapper<T> setSql(String setSql);
public UpdateWrapper<T> setSql(boolean condition, String setSql);
// Lambda conversion
public LambdaUpdateWrapper<T> lambda();
// All QueryWrapper methods are also available for WHERE conditions
// eq, ne, gt, ge, lt, le, between, like, in, etc.
}Lambda-style update wrapper with type-safe property references.
/**
* Lambda update wrapper for type-safe property references
* @param <T> Entity type
*/
public class LambdaUpdateWrapper<T> extends AbstractLambdaWrapper<T, LambdaUpdateWrapper<T>>
implements Update<LambdaUpdateWrapper<T>, SFunction<T, ?>> {
// Set operations
public LambdaUpdateWrapper<T> set(SFunction<T, ?> fn, Object val);
public LambdaUpdateWrapper<T> set(boolean condition, SFunction<T, ?> fn, Object val);
public LambdaUpdateWrapper<T> setSql(String setSql);
public LambdaUpdateWrapper<T> setSql(boolean condition, String setSql);
// All LambdaQueryWrapper methods are also available for WHERE conditions
// eq, ne, gt, ge, lt, le, between, like, in, etc.
}Factory class for creating wrapper instances.
/**
* Utility class for creating wrapper instances
*/
public final class Wrappers {
/**
* Create an empty QueryWrapper
*/
public static <T> QueryWrapper<T> query();
/**
* Create a QueryWrapper with entity
*/
public static <T> QueryWrapper<T> query(T entity);
/**
* Create an empty LambdaQueryWrapper
*/
public static <T> LambdaQueryWrapper<T> lambdaQuery();
/**
* Create a LambdaQueryWrapper with entity
*/
public static <T> LambdaQueryWrapper<T> lambdaQuery(T entity);
/**
* Create an empty UpdateWrapper
*/
public static <T> UpdateWrapper<T> update();
/**
* Create an UpdateWrapper with entity
*/
public static <T> UpdateWrapper<T> update(T entity);
/**
* Create an empty LambdaUpdateWrapper
*/
public static <T> LambdaUpdateWrapper<T> lambdaUpdate();
/**
* Create a LambdaUpdateWrapper with entity
*/
public static <T> LambdaUpdateWrapper<T> lambdaUpdate(T entity);
/**
* Create an empty wrapper (no conditions)
*/
public static <T> QueryWrapper<T> emptyWrapper();
}Factory class for creating chain wrapper instances, providing fluent chainable query and update operations.
/**
* Utility class for creating chain wrapper instances
*/
public final class ChainWrappers {
/**
* Create a LambdaQueryChainWrapper for fluent querying
* @param mapper BaseMapper instance
* @return LambdaQueryChainWrapper instance
*/
public static <T> LambdaQueryChainWrapper<T> lambdaQueryChain(BaseMapper<T> mapper);
/**
* Create a QueryChainWrapper for fluent querying
* @param mapper BaseMapper instance
* @return QueryChainWrapper instance
*/
public static <T> QueryChainWrapper<T> queryChain(BaseMapper<T> mapper);
/**
* Create a LambdaUpdateChainWrapper for fluent updating
* @param mapper BaseMapper instance
* @return LambdaUpdateChainWrapper instance
*/
public static <T> LambdaUpdateChainWrapper<T> lambdaUpdateChain(BaseMapper<T> mapper);
/**
* Create an UpdateChainWrapper for fluent updating
* @param mapper BaseMapper instance
* @return UpdateChainWrapper instance
*/
public static <T> UpdateChainWrapper<T> updateChain(BaseMapper<T> mapper);
}Basic Query Conditions:
// String-based QueryWrapper
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "John")
.gt("age", 18)
.like("email", "@gmail.com")
.isNotNull("phone");
List<User> users = userMapper.selectList(wrapper);
// Lambda-based LambdaQueryWrapper (type-safe)
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(User::getName, "John")
.gt(User::getAge, 18)
.like(User::getEmail, "@gmail.com")
.isNotNull(User::getPhone);
List<User> users = userMapper.selectList(lambdaWrapper);Complex Logical Conditions:
// AND and OR combinations
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1)
.and(w -> w.eq("type", "VIP").or().gt("score", 1000))
.or(w -> w.eq("level", "ADMIN"));
// Generates: WHERE status = 1 AND (type = 'VIP' OR score > 1000) OR level = 'ADMIN'
// Nested conditions
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, 1)
.nested(w -> w.eq(User::getType, "VIP")
.or()
.gt(User::getScore, 1000));
// Generates: WHERE status = 1 AND (type = 'VIP' OR score > 1000)Range and Collection Conditions:
// Range conditions
wrapper.between("age", 18, 65)
.notBetween("score", 0, 60);
// Collection conditions
List<String> cities = Arrays.asList("Beijing", "Shanghai", "Guangzhou");
wrapper.in("city", cities)
.notIn("status", 0, -1);
// Subquery conditions
wrapper.inSql("dept_id", "SELECT id FROM department WHERE name = 'IT'")
.notInSql("role_id", "SELECT id FROM role WHERE name = 'GUEST'");String Matching:
// Different LIKE patterns
wrapper.like("name", "John") // name LIKE '%John%'
.likeLeft("email", "gmail.com") // email LIKE '%gmail.com'
.likeRight("phone", "138") // phone LIKE '138%'
.notLike("address", "temp"); // address NOT LIKE '%temp%'Ordering and Grouping:
// Ordering
wrapper.orderByAsc("create_time")
.orderByDesc("update_time", "id");
// Dynamic ordering
boolean sortByAge = true;
wrapper.orderBy(sortByAge, true, "age"); // Conditional ascending sort
// Grouping with HAVING
wrapper.select("dept_id", "COUNT(*) as count")
.groupBy("dept_id")
.having("COUNT(*) > 5");Column Selection:
// Select specific columns
wrapper.select("id", "name", "email");
// Lambda column selection
lambdaWrapper.select(User::getId, User::getName, User::getEmail);
// Conditional column selection
wrapper.select(User.class, info -> !info.getColumn().equals("password"));Update Operations:
// UpdateWrapper for setting values
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("status", 1)
.set("update_time", LocalDateTime.now())
.eq("id", 123);
userMapper.update(null, updateWrapper);
// LambdaUpdateWrapper (type-safe)
LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.set(User::getStatus, 1)
.set(User::getUpdateTime, LocalDateTime.now())
.eq(User::getId, 123);
userMapper.update(null, lambdaUpdate);
// Update with entity and conditions
User updateUser = new User();
updateUser.setStatus(1);
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("dept_id", 10).gt("age", 25);
userMapper.update(updateUser, wrapper);Using Wrappers Utility:
// Factory methods for cleaner code
import static com.baomidou.mybatisplus.core.conditions.Wrappers.*;
// Query wrappers
List<User> users = userMapper.selectList(
query(User.class).eq("status", 1).gt("age", 18)
);
List<User> activeUsers = userMapper.selectList(
lambdaQuery(User.class).eq(User::getStatus, 1)
.gt(User::getAge, 18)
);
// Update wrappers
userMapper.update(null,
update(User.class).set("status", 0).eq("id", 123)
);
userMapper.update(null,
lambdaUpdate(User.class).set(User::getStatus, 0)
.eq(User::getId, 123)
);Custom SQL and Advanced Features:
// Custom SQL fragments
wrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", "2023-11");
// Raw SQL at the end (use with caution)
wrapper.eq("status", 1).last("LIMIT 10");
// Existence conditions
wrapper.exists("SELECT 1 FROM user_role WHERE user_id = user.id AND role_id = 1")
.notExists("SELECT 1 FROM user_ban WHERE user_id = user.id");
// Conditional building
String name = getNameParam(); // Could be null
Integer minAge = getMinAgeParam(); // Could be null
wrapper.eq(StringUtils.isNotBlank(name), "name", name)
.ge(minAge != null, "age", minAge);Performance Tips:
LambdaQueryWrapper for type safety and refactoring supportselect() methodslast() sparingly and never with user input (SQL injection risk)Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus