Dynamic Query Construction Using MyBatis-Plus Wrapper Classes
MyBatis-Plus provides a robust abstraction layer over standard MyBatis operations through its Wrapper API, enabling programmatic SQL generation without XML configuration. The architecture centers around the Wrapper abstract class, which serves as the foundasion for all condition constructors.
Class Hierarchy
The inheritance structure follows a clear pattern:
Wrapper<T>: Base abstract class defining core functionalityAbstractWrapper<T, R, Children>: Implements SQL fragment generation for WHERE clausesQueryWrapper<T>: Concrete implementation for SELECT operations using string column referencesUpdateWrapper<T>: Concrete implementation for UPDATE operationsAbstractLambdaWrapper<T, Children>: Adds Lambda expression support for type-safe column referencingLambdaQueryWrapper<T>: Type-safe query construction using method referencesLambdaUpdateWrapper<T>: Type-safe update condition building
Predicate Methods
The API provides fluent methods for constructing WHERE clauses:
eq(column, value): Equality comparisonne(column, value): Inequality comparisonlike(column, pattern): Fuzzy matching with % wildcardslikeRight(column, prefix): Prefix matching (column LIKE 'prefix%')gt(column, value): Greater than comparisonge(column, value): Greater than or equallt(column, value): Less than comparisonle(column, value): Less than or equalbetween(column, min, max): Range inclusion checkisNull(column): NULL value checkisNotNull(column): Non-NULL checkorderByAsc(column): Ascending sortorderByDesc(column): Descending sort
Implementing QueryWrapper
For dynamic SELECT statements, QueryWrapper enables method chaining to assemble complex criteria:
public void fetchActiveUsers() {
QueryWrapper<SysUser> criteria = new QueryWrapper<>();
criteria.likeRight("user_name", "admin")
.eq("status", 1)
.isNotNull("email_address")
.ge("login_count", 5);
List<SysUser> results = userDao.selectList(criteria);
results.forEach(System.out::println);
}
This generates SQL equivalent to:
SELECT * FROM sys_user
WHERE user_name LIKE 'admin%'
AND status = 1
AND email_address IS NOT NULL
AND login_count >= 5
Sorting and Pagination
Multiple ordering rules stack sequentialy:
public List<SysUser> getOrderedRecords() {
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("priority_level")
.orderByAsc("registration_date");
return userMapper.selectList(wrapper);
}
Corresponding SQL:
SELECT * FROM sys_user
ORDER BY priority_level DESC, registration_date ASC
Batch Update Operations
UpdateWrapper facilitates conditional modifications without loading entities into memory:
public void deactivateInactiveAccounts() {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("status", 0)
.set("remarks", "Auto-disabled due to inactivity")
.isNull("last_login_time")
.lt("create_time", LocalDateTime.now().minusYears(1));
userMapper.update(null, updateWrapper);
}
Lambda-based Type Safety
To eliminate hardcoded column strings, LambdaQueryWrapper uses method references:
public List<SysUser> fetchByLambda() {
LambdaQueryWrapper<SysUser> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.select(SysUser::getId, SysUser::getUserName)
.like(SysUser::getEmailAddress, "@company.com")
.ge(SysUser::getScore, 100)
.orderByDesc(SysUser::getCreateTime);
return userMapper.selectList(lambdaWrapper);
}
This approach provides compile-time verification of column existence while maintaining identical runtime performence to string-based wrappers.